├── .NET ├── .gitignore ├── Benchmark │ ├── Benchmark.csproj │ ├── Extension.cs │ └── Program.cs ├── OneShot.sln ├── OneShotInjection │ └── OneShotInjection.csproj ├── Test │ └── Test.csproj └── global.json ├── .editorconfig ├── .github └── workflows │ ├── dotnet.yml │ ├── nuget-publish.yml │ ├── release-upm.yml │ └── unity-test.yml ├── .gitignore ├── Assets ├── Benchmark.meta ├── Benchmark │ ├── Benchmark.asmdef │ ├── Benchmark.asmdef.meta │ ├── BenchmarkCreateInstance.cs │ └── BenchmarkCreateInstance.cs.meta ├── FooInstaller.cs ├── FooInstaller.cs.meta ├── Sample.unity ├── Sample.unity.meta ├── Tests.meta └── Tests │ ├── Fixture.cs │ ├── Fixture.cs.meta │ ├── TestCircularCheck.cs │ ├── TestCircularCheck.cs.meta │ ├── TestGeneric.cs │ ├── TestGeneric.cs.meta │ ├── TestLabel.cs │ ├── TestLabel.cs.meta │ ├── TestLifetime.cs │ ├── TestLifetime.cs.meta │ ├── TestMultithread.cs │ ├── TestMultithread.cs.meta │ ├── TestOneShot.cs │ ├── TestOneShot.cs.meta │ ├── TestWithBuilder.cs │ ├── TestWithBuilder.cs.meta │ ├── Tests.asmdef │ └── Tests.asmdef.meta ├── LICENSE ├── Packages ├── com.quabug.one-shot-injection │ ├── ContainerComponent.cs │ ├── ContainerComponent.cs.meta │ ├── Injector.cs │ ├── Injector.cs.meta │ ├── OneShot.asmdef │ ├── OneShot.asmdef.meta │ ├── OneShot.cs │ ├── OneShot.cs.meta │ ├── StopInjection.cs │ ├── StopInjection.cs.meta │ ├── package.json │ └── package.json.meta ├── manifest.json └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── MemorySettings.asset ├── NavMeshAreas.asset ├── PackageManagerSettings.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── SceneTemplateSettings.json ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset ├── VersionControlSettings.asset ├── XRSettings.asset └── boot.config └── README.md /.NET/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # Rider 12 | .idea 13 | 14 | # User-specific files 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | build/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Oo]ut/ 32 | msbuild.log 33 | msbuild.err 34 | msbuild.wrn 35 | 36 | # Visual Studio 2015 37 | .vs/ -------------------------------------------------------------------------------- /.NET/Benchmark/Benchmark.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.NET/Benchmark/Extension.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using System.Reflection; 3 | 4 | namespace Benchmark; 5 | 6 | public static class Extension 7 | { 8 | public static Func Compile(this ConstructorInfo ci) 9 | { 10 | var @params = Expression.Parameter(typeof(object[])); 11 | var args = ci.GetParameters().Select((parameter, index) => Expression.Convert( 12 | Expression.ArrayIndex(@params, Expression.Constant(index)), 13 | parameter.ParameterType) 14 | ).Cast().ToArray(); 15 | var @new = Expression.New(ci, args); 16 | var lambda = Expression.Lambda(typeof(Func), Expression.Convert(@new, typeof(object)), @params); 17 | return (Func) lambda.Compile(); 18 | } 19 | } -------------------------------------------------------------------------------- /.NET/Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using System.Numerics; 4 | using System.Reflection; 5 | using Benchmark; 6 | using BenchmarkDotNet.Attributes; 7 | using BenchmarkDotNet.Running; 8 | 9 | Console.WriteLine("Hello, World!"); 10 | 11 | var summary = BenchmarkRunner.Run(typeof(Program).Assembly); 12 | 13 | public class BenchmarkEmpty 14 | { 15 | class Empty {} 16 | 17 | private readonly Type _type; 18 | private readonly ConstructorInfo _ci; 19 | private readonly Func _creator; 20 | 21 | public BenchmarkEmpty() 22 | { 23 | _type = typeof(Empty); 24 | _ci = _type.GetConstructors()[0]; 25 | _creator = _ci.Compile(); 26 | } 27 | 28 | [Benchmark] public object EmptyNew() => new(); 29 | [Benchmark] public object EmptyCreateInstance() => Activator.CreateInstance(_type); 30 | [Benchmark] public object EmptyConstructorInvoke() => _ci.Invoke(Array.Empty()); 31 | [Benchmark] public object EmptyConstructorInvokeWithInstance() 32 | { 33 | var instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(_type); 34 | return _ci.Invoke(instance, Array.Empty()); 35 | } 36 | [Benchmark] public object EmptyExpression() => _creator(Array.Empty()); 37 | } 38 | 39 | public class BenchmarkComplex 40 | { 41 | class Complex 42 | { 43 | public int I; 44 | public long L; 45 | public double D; 46 | public string S; 47 | public Matrix4x4 M; 48 | 49 | public Complex(int i, long l, double d, string s, Matrix4x4 m) 50 | { 51 | I = i; 52 | L = l; 53 | D = d; 54 | S = s; 55 | M = m; 56 | } 57 | } 58 | 59 | private readonly Type _type; 60 | private readonly ConstructorInfo _ci; 61 | private readonly Func _creator; 62 | private readonly object[] _args; 63 | 64 | public BenchmarkComplex() 65 | { 66 | _type = typeof(Complex); 67 | _ci = _type.GetConstructors()[0]; 68 | _creator = _ci.Compile(); 69 | _args = new object[] { 123, 234L, 111.111, "fjklfd", Matrix4x4.Identity }; 70 | } 71 | 72 | [Benchmark] public object ComplexNew() => new Complex(123, 234L, 111.111, "fjklfd", Matrix4x4.Identity); 73 | [Benchmark] public object ComplexCreateInstance() => Activator.CreateInstance(_type, _args); 74 | [Benchmark] public object ComplexConstructorInvoke() => _ci.Invoke(_args); 75 | [Benchmark] public object ComplexConstructorInvokeWithInstance() 76 | { 77 | var instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(_type); 78 | return _ci.Invoke(instance, _args); 79 | } 80 | [Benchmark] public object ComplexExpression() => _creator(_args); 81 | } 82 | -------------------------------------------------------------------------------- /.NET/OneShot.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneShotInjection", "OneShotInjection\OneShotInjection.csproj", "{84622D1A-E5DC-43F1-AC7E-DDFA8EC04238}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{7DDEDBDE-A1CE-4B5A-BE14-1BE8B27E14D9}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{4097055A-0D74-42A5-8AA0-F0EADB2C5B5E}" 8 | EndProject 9 | Global 10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 11 | Debug|Any CPU = Debug|Any CPU 12 | Release|Any CPU = Release|Any CPU 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {84622D1A-E5DC-43F1-AC7E-DDFA8EC04238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 16 | {84622D1A-E5DC-43F1-AC7E-DDFA8EC04238}.Debug|Any CPU.Build.0 = Debug|Any CPU 17 | {84622D1A-E5DC-43F1-AC7E-DDFA8EC04238}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {84622D1A-E5DC-43F1-AC7E-DDFA8EC04238}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {7DDEDBDE-A1CE-4B5A-BE14-1BE8B27E14D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {7DDEDBDE-A1CE-4B5A-BE14-1BE8B27E14D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {7DDEDBDE-A1CE-4B5A-BE14-1BE8B27E14D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {7DDEDBDE-A1CE-4B5A-BE14-1BE8B27E14D9}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {4097055A-0D74-42A5-8AA0-F0EADB2C5B5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {4097055A-0D74-42A5-8AA0-F0EADB2C5B5E}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {4097055A-0D74-42A5-8AA0-F0EADB2C5B5E}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {4097055A-0D74-42A5-8AA0-F0EADB2C5B5E}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /.NET/OneShotInjection/OneShotInjection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OneShot 5 | OneShot 6 | 3.0.1 7 | quabug 8 | 9 9 | README.md 10 | OneShot 11 | A single file DI container 12 | MIT 13 | https://github.com/quabug/OneShot 14 | netstandard2.1 15 | false 16 | enable 17 | true 18 | 6 19 | AllEnabledByDefault 20 | true 21 | true 22 | true 23 | true 24 | true 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | README.md 40 | true 41 | README.md 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.NET/Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | disable 4 | disable 5 | true 6 | false 7 | 9 8 | net6.0;net7.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | %(FileName)%(Extension) 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /.NET/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "7.0.306", // https://github.com/microsoft/testfx/issues/1733 4 | "rollForward": "disable" 5 | } 6 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://github.com/dotnet/runtime/blob/main/.editorconfig 2 | 3 | # editorconfig.org 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | # Default settings: 9 | # A newline ending every file 10 | # Use 4 spaces as indentation 11 | [*] 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 4 15 | trim_trailing_whitespace = true 16 | charset = utf-8 17 | end_of_line = lf 18 | 19 | # ReSharper properties 20 | resharper_csharp_wrap_parameters_style = chop_if_long 21 | 22 | # Generated code 23 | [*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}] 24 | generated_code = true 25 | 26 | # C# files 27 | [*.cs] 28 | # New line preferences 29 | csharp_new_line_before_open_brace = all 30 | csharp_new_line_before_else = true 31 | csharp_new_line_before_catch = true 32 | csharp_new_line_before_finally = true 33 | csharp_new_line_before_members_in_object_initializers = true 34 | csharp_new_line_before_members_in_anonymous_types = true 35 | csharp_new_line_between_query_expression_clauses = true 36 | 37 | # Indentation preferences 38 | csharp_indent_block_contents = true 39 | csharp_indent_braces = false 40 | csharp_indent_case_contents = true 41 | csharp_indent_case_contents_when_block = true 42 | csharp_indent_switch_labels = true 43 | csharp_indent_labels = one_less_than_current 44 | 45 | # avoid this. unless absolutely necessary 46 | dotnet_style_qualification_for_field = false:suggestion 47 | dotnet_style_qualification_for_property = false:suggestion 48 | dotnet_style_qualification_for_method = false:suggestion 49 | dotnet_style_qualification_for_event = false:suggestion 50 | 51 | # Types: use keywords instead of BCL types, and permit var only when the type is clear 52 | csharp_style_var_for_built_in_types = false:suggestion 53 | csharp_style_var_when_type_is_apparent = true:none 54 | csharp_style_var_elsewhere = false:suggestion 55 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 56 | dotnet_style_predefined_type_for_member_access = true:suggestion 57 | 58 | # name all constant fields using PascalCase 59 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning 60 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields 61 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style 62 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 63 | dotnet_naming_symbols.constant_fields.required_modifiers = const 64 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 65 | 66 | # static fields should have s_ prefix 67 | dotnet_naming_rule.static_fields_should_have_prefix.severity = warning 68 | dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields 69 | dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style 70 | dotnet_naming_symbols.static_fields.applicable_kinds = field 71 | dotnet_naming_symbols.static_fields.required_modifiers = static 72 | dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected 73 | dotnet_naming_style.static_prefix_style.required_prefix = s_ 74 | dotnet_naming_style.static_prefix_style.capitalization = camel_case 75 | 76 | # internal and private fields should be _camelCase 77 | dotnet_naming_rule.camel_case_for_private_internal_fields.severity = warning 78 | dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields 79 | dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style 80 | dotnet_naming_symbols.private_internal_fields.applicable_kinds = field 81 | dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal 82 | dotnet_naming_style.camel_case_underscore_style.required_prefix = _ 83 | dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case 84 | 85 | # Code style defaults 86 | csharp_using_directive_placement = outside_namespace:suggestion 87 | dotnet_sort_system_directives_first = true 88 | csharp_prefer_braces = true:silent 89 | csharp_preserve_single_line_blocks = true:none 90 | csharp_preserve_single_line_statements = false:none 91 | csharp_prefer_static_local_function = true:suggestion 92 | csharp_prefer_simple_using_statement = false:none 93 | csharp_style_prefer_switch_expression = true:suggestion 94 | dotnet_style_readonly_field = true:suggestion 95 | 96 | # Expression-level preferences 97 | dotnet_style_object_initializer = true:suggestion 98 | dotnet_style_collection_initializer = true:suggestion 99 | dotnet_style_explicit_tuple_names = true:suggestion 100 | dotnet_style_coalesce_expression = true:suggestion 101 | dotnet_style_null_propagation = true:suggestion 102 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 103 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 104 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 105 | dotnet_style_prefer_auto_properties = true:suggestion 106 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 107 | dotnet_style_prefer_conditional_expression_over_return = true:silent 108 | csharp_prefer_simple_default_expression = true:suggestion 109 | 110 | # Expression-bodied members 111 | csharp_style_expression_bodied_methods = true:silent 112 | csharp_style_expression_bodied_constructors = true:silent 113 | csharp_style_expression_bodied_operators = true:silent 114 | csharp_style_expression_bodied_properties = true:silent 115 | csharp_style_expression_bodied_indexers = true:silent 116 | csharp_style_expression_bodied_accessors = true:silent 117 | csharp_style_expression_bodied_lambdas = true:silent 118 | csharp_style_expression_bodied_local_functions = true:silent 119 | 120 | # Pattern matching 121 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 122 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 123 | csharp_style_inlined_variable_declaration = true:suggestion 124 | 125 | # Null checking preferences 126 | csharp_style_throw_expression = true:suggestion 127 | csharp_style_conditional_delegate_call = true:suggestion 128 | 129 | # Other features 130 | csharp_style_prefer_index_operator = false:none 131 | csharp_style_prefer_range_operator = false:none 132 | csharp_style_pattern_local_over_anonymous_function = false:none 133 | 134 | # Space preferences 135 | csharp_space_after_cast = false 136 | csharp_space_after_colon_in_inheritance_clause = true 137 | csharp_space_after_comma = true 138 | csharp_space_after_dot = false 139 | csharp_space_after_keywords_in_control_flow_statements = true 140 | csharp_space_after_semicolon_in_for_statement = true 141 | csharp_space_around_binary_operators = before_and_after 142 | csharp_space_around_declaration_statements = do_not_ignore 143 | csharp_space_before_colon_in_inheritance_clause = true 144 | csharp_space_before_comma = false 145 | csharp_space_before_dot = false 146 | csharp_space_before_open_square_brackets = false 147 | csharp_space_before_semicolon_in_for_statement = false 148 | csharp_space_between_empty_square_brackets = false 149 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 150 | csharp_space_between_method_call_name_and_opening_parenthesis = false 151 | csharp_space_between_method_call_parameter_list_parentheses = false 152 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 153 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 154 | csharp_space_between_method_declaration_parameter_list_parentheses = false 155 | csharp_space_between_parentheses = false 156 | csharp_space_between_square_brackets = false 157 | 158 | # Namespace settings 159 | csharp_style_namespace_declarations = file_scoped 160 | 161 | # C++ Files 162 | [*.{cpp,h,in}] 163 | curly_bracket_next_line = true 164 | indent_brace_style = Allman 165 | 166 | # Xml project files 167 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] 168 | indent_size = 2 169 | 170 | [*.{csproj,vbproj,proj,nativeproj,locproj}] 171 | charset = utf-8 172 | 173 | # Xml build files 174 | [*.builds] 175 | indent_size = 2 176 | 177 | # Xml files 178 | [*.{xml,stylecop,resx,ruleset}] 179 | indent_size = 2 180 | 181 | # Xml config files 182 | [*.{props,targets,config,nuspec}] 183 | indent_size = 2 184 | 185 | # YAML config files 186 | [*.{yml,yaml}] 187 | indent_size = 2 188 | 189 | [*.json] 190 | indent_size = 2 191 | 192 | # Shell scripts 193 | [*.sh] 194 | indent_size = 4 195 | end_of_line = lf 196 | 197 | [*.{cmd,bat}] 198 | end_of_line = crlf 199 | 200 | # Xml config files 201 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 202 | indent_size = 2 203 | 204 | # https://github.com/dotnet/aspnetcore/blob/main/.editorconfig 205 | [*.{cs,vb}] 206 | # CA1062: Validate arguments of public methods 207 | dotnet_diagnostic.CA1062.severity = none 208 | 209 | # SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time 210 | dotnet_diagnostic.SYSLIB1054.severity = warning 211 | 212 | # CA1018: Mark attributes with AttributeUsageAttribute 213 | dotnet_diagnostic.CA1018.severity = warning 214 | 215 | # CA1047: Do not declare protected member in sealed type 216 | dotnet_diagnostic.CA1047.severity = warning 217 | 218 | # CA1305: Specify IFormatProvider 219 | dotnet_diagnostic.CA1305.severity = warning 220 | 221 | # CA1507: Use nameof to express symbol names 222 | dotnet_diagnostic.CA1507.severity = warning 223 | 224 | # CA1510: Use ArgumentNullException throw helper 225 | dotnet_diagnostic.CA1510.severity = warning 226 | 227 | # CA1511: Use ArgumentException throw helper 228 | dotnet_diagnostic.CA1511.severity = warning 229 | 230 | # CA1512: Use ArgumentOutOfRangeException throw helper 231 | dotnet_diagnostic.CA1512.severity = warning 232 | 233 | # CA1513: Use ObjectDisposedException throw helper 234 | dotnet_diagnostic.CA1513.severity = warning 235 | 236 | # CA1725: Parameter names should match base declaration 237 | dotnet_diagnostic.CA1725.severity = suggestion 238 | 239 | # CA1802: Use literals where appropriate 240 | dotnet_diagnostic.CA1802.severity = warning 241 | 242 | # CA1805: Do not initialize unnecessarily 243 | dotnet_diagnostic.CA1805.severity = warning 244 | 245 | # CA1810: Do not initialize unnecessarily 246 | dotnet_diagnostic.CA1810.severity = warning 247 | 248 | # CA1821: Remove empty Finalizers 249 | dotnet_diagnostic.CA1821.severity = warning 250 | 251 | # CA1822: Make member static 252 | dotnet_diagnostic.CA1822.severity = warning 253 | dotnet_code_quality.CA1822.api_surface = private, internal 254 | 255 | # CA1823: Avoid unused private fields 256 | dotnet_diagnostic.CA1823.severity = warning 257 | 258 | # CA1825: Avoid zero-length array allocations 259 | dotnet_diagnostic.CA1825.severity = warning 260 | 261 | # CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly 262 | dotnet_diagnostic.CA1826.severity = warning 263 | 264 | # CA1827: Do not use Count() or LongCount() when Any() can be used 265 | dotnet_diagnostic.CA1827.severity = warning 266 | 267 | # CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used 268 | dotnet_diagnostic.CA1828.severity = warning 269 | 270 | # CA1829: Use Length/Count property instead of Count() when available 271 | dotnet_diagnostic.CA1829.severity = warning 272 | 273 | # CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder 274 | dotnet_diagnostic.CA1830.severity = warning 275 | 276 | # CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 277 | dotnet_diagnostic.CA1831.severity = warning 278 | 279 | # CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 280 | dotnet_diagnostic.CA1832.severity = warning 281 | 282 | # CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 283 | dotnet_diagnostic.CA1833.severity = warning 284 | 285 | # CA1834: Consider using 'StringBuilder.Append(char)' when applicable 286 | dotnet_diagnostic.CA1834.severity = warning 287 | 288 | # CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' 289 | dotnet_diagnostic.CA1835.severity = warning 290 | 291 | # CA1836: Prefer IsEmpty over Count 292 | dotnet_diagnostic.CA1836.severity = warning 293 | 294 | # CA1837: Use 'Environment.ProcessId' 295 | dotnet_diagnostic.CA1837.severity = warning 296 | 297 | # CA1838: Avoid 'StringBuilder' parameters for P/Invokes 298 | dotnet_diagnostic.CA1838.severity = warning 299 | 300 | # CA1839: Use 'Environment.ProcessPath' 301 | dotnet_diagnostic.CA1839.severity = warning 302 | 303 | # CA1840: Use 'Environment.CurrentManagedThreadId' 304 | dotnet_diagnostic.CA1840.severity = warning 305 | 306 | # CA1841: Prefer Dictionary.Contains methods 307 | dotnet_diagnostic.CA1841.severity = warning 308 | 309 | # CA1842: Do not use 'WhenAll' with a single task 310 | dotnet_diagnostic.CA1842.severity = warning 311 | 312 | # CA1843: Do not use 'WaitAll' with a single task 313 | dotnet_diagnostic.CA1843.severity = warning 314 | 315 | # CA1844: Provide memory-based overrides of async methods when subclassing 'Stream' 316 | dotnet_diagnostic.CA1844.severity = warning 317 | 318 | # CA1845: Use span-based 'string.Concat' 319 | dotnet_diagnostic.CA1845.severity = warning 320 | 321 | # CA1846: Prefer AsSpan over Substring 322 | dotnet_diagnostic.CA1846.severity = warning 323 | 324 | # CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters 325 | dotnet_diagnostic.CA1847.severity = warning 326 | 327 | # CA1852: Seal internal types 328 | dotnet_diagnostic.CA1852.severity = warning 329 | 330 | # CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method 331 | dotnet_diagnostic.CA1854.severity = warning 332 | 333 | # CA1855: Prefer 'Clear' over 'Fill' 334 | dotnet_diagnostic.CA1855.severity = warning 335 | 336 | # CA1856: Incorrect usage of ConstantExpected attribute 337 | dotnet_diagnostic.CA1856.severity = error 338 | 339 | # CA1857: A constant is expected for the parameter 340 | dotnet_diagnostic.CA1857.severity = warning 341 | 342 | # CA1858: Use 'StartsWith' instead of 'IndexOf' 343 | dotnet_diagnostic.CA1858.severity = warning 344 | 345 | # CA2007: Consider calling ConfigureAwait on the awaited task 346 | dotnet_diagnostic.CA2007.severity = warning 347 | 348 | # CA2008: Do not create tasks without passing a TaskScheduler 349 | dotnet_diagnostic.CA2008.severity = warning 350 | 351 | # CA2009: Do not call ToImmutableCollection on an ImmutableCollection value 352 | dotnet_diagnostic.CA2009.severity = warning 353 | 354 | # CA2011: Avoid infinite recursion 355 | dotnet_diagnostic.CA2011.severity = warning 356 | 357 | # CA2012: Use ValueTask correctly 358 | dotnet_diagnostic.CA2012.severity = warning 359 | 360 | # CA2013: Do not use ReferenceEquals with value types 361 | dotnet_diagnostic.CA2013.severity = warning 362 | 363 | # CA2014: Do not use stackalloc in loops. 364 | dotnet_diagnostic.CA2014.severity = warning 365 | 366 | # CA2016: Forward the 'CancellationToken' parameter to methods that take one 367 | dotnet_diagnostic.CA2016.severity = warning 368 | 369 | # CA2200: Rethrow to preserve stack details 370 | dotnet_diagnostic.CA2200.severity = warning 371 | 372 | # CA2208: Instantiate argument exceptions correctly 373 | dotnet_diagnostic.CA2208.severity = warning 374 | 375 | # CA2245: Do not assign a property to itself 376 | dotnet_diagnostic.CA2245.severity = warning 377 | 378 | # CA2246: Assigning symbol and its member in the same statement 379 | dotnet_diagnostic.CA2246.severity = warning 380 | 381 | # CA2249: Use string.Contains instead of string.IndexOf to improve readability. 382 | dotnet_diagnostic.CA2249.severity = warning 383 | 384 | # IDE0005: Remove unnecessary usings 385 | dotnet_diagnostic.IDE0005.severity = warning 386 | 387 | # IDE0011: Curly braces to surround blocks of code 388 | dotnet_diagnostic.IDE0011.severity = none 389 | 390 | # IDE0020: Use pattern matching to avoid is check followed by a cast (with variable) 391 | dotnet_diagnostic.IDE0020.severity = warning 392 | 393 | # IDE0029: Use coalesce expression (non-nullable types) 394 | dotnet_diagnostic.IDE0029.severity = warning 395 | 396 | # IDE0030: Use coalesce expression (nullable types) 397 | dotnet_diagnostic.IDE0030.severity = warning 398 | 399 | # IDE0031: Use null propagation 400 | dotnet_diagnostic.IDE0031.severity = warning 401 | 402 | # IDE0035: Remove unreachable code 403 | dotnet_diagnostic.IDE0035.severity = warning 404 | 405 | # IDE0036: Order modifiers 406 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 407 | dotnet_diagnostic.IDE0036.severity = warning 408 | 409 | # IDE0038: Use pattern matching to avoid is check followed by a cast (without variable) 410 | dotnet_diagnostic.IDE0038.severity = warning 411 | 412 | # IDE0043: Format string contains invalid placeholder 413 | dotnet_diagnostic.IDE0043.severity = warning 414 | 415 | # IDE0044: Make field readonly 416 | dotnet_diagnostic.IDE0044.severity = warning 417 | 418 | # IDE0051: Remove unused private members 419 | dotnet_diagnostic.IDE0051.severity = warning 420 | 421 | # IDE0055: All formatting rules 422 | dotnet_diagnostic.IDE0055.severity = warning 423 | 424 | # IDE0059: Unnecessary assignment to a value 425 | dotnet_diagnostic.IDE0059.severity = warning 426 | 427 | # IDE0060: Remove unused parameter 428 | dotnet_code_quality_unused_parameters = non_public 429 | dotnet_diagnostic.IDE0060.severity = warning 430 | 431 | # IDE0062: Make local function static 432 | dotnet_diagnostic.IDE0062.severity = warning 433 | 434 | # IDE0073: File header 435 | #dotnet_diagnostic.IDE0073.severity = warning 436 | #file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license. 437 | 438 | # IDE0161: Convert to file-scoped namespace 439 | dotnet_diagnostic.IDE0161.severity = warning 440 | 441 | # IDE0200: Lambda expression can be removed 442 | dotnet_diagnostic.IDE0200.severity = warning 443 | 444 | # IDE1006: Naming rule violation 445 | dotnet_diagnostic.IDE1006.severity = warning 446 | 447 | # IDE2000: Disallow multiple blank lines 448 | dotnet_style_allow_multiple_blank_lines_experimental = false 449 | dotnet_diagnostic.IDE2000.severity = warning 450 | # 451 | # [{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,scripts,stress}/**.cs}] 452 | # # CA1018: Mark attributes with AttributeUsageAttribute 453 | # dotnet_diagnostic.CA1018.severity = suggestion 454 | # # CA1507: Use nameof to express symbol names 455 | # dotnet_diagnostic.CA1507.severity = suggestion 456 | # # CA1510: Use ArgumentNullException throw helper 457 | # dotnet_diagnostic.CA1510.severity = suggestion 458 | # # CA1511: Use ArgumentException throw helper 459 | # dotnet_diagnostic.CA1511.severity = suggestion 460 | # # CA1512: Use ArgumentOutOfRangeException throw helper 461 | # dotnet_diagnostic.CA1512.severity = suggestion 462 | # # CA1513: Use ObjectDisposedException throw helper 463 | # dotnet_diagnostic.CA1513.severity = suggestion 464 | # # CA1802: Use literals where appropriate 465 | # dotnet_diagnostic.CA1802.severity = suggestion 466 | # # CA1805: Do not initialize unnecessarily 467 | # dotnet_diagnostic.CA1805.severity = suggestion 468 | # # CA1810: Do not initialize unnecessarily 469 | # dotnet_diagnostic.CA1810.severity = suggestion 470 | # # CA1822: Make member static 471 | # dotnet_diagnostic.CA1822.severity = suggestion 472 | # # CA1823: Avoid zero-length array allocations 473 | # dotnet_diagnostic.CA1825.severity = suggestion 474 | # # CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly 475 | # dotnet_diagnostic.CA1826.severity = suggestion 476 | # # CA1827: Do not use Count() or LongCount() when Any() can be used 477 | # dotnet_diagnostic.CA1827.severity = suggestion 478 | # # CA1829: Use Length/Count property instead of Count() when available 479 | # dotnet_diagnostic.CA1829.severity = suggestion 480 | # # CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 481 | # dotnet_diagnostic.CA1831.severity = suggestion 482 | # # CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 483 | # dotnet_diagnostic.CA1832.severity = suggestion 484 | # # CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate 485 | # dotnet_diagnostic.CA1833.severity = suggestion 486 | # # CA1834: Consider using 'StringBuilder.Append(char)' when applicable 487 | # dotnet_diagnostic.CA1834.severity = suggestion 488 | # # CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' 489 | # dotnet_diagnostic.CA1835.severity = suggestion 490 | # # CA1837: Use 'Environment.ProcessId' 491 | # dotnet_diagnostic.CA1837.severity = suggestion 492 | # # CA1838: Avoid 'StringBuilder' parameters for P/Invokes 493 | # dotnet_diagnostic.CA1838.severity = suggestion 494 | # # CA1841: Prefer Dictionary.Contains methods 495 | # dotnet_diagnostic.CA1841.severity = suggestion 496 | # # CA1844: Provide memory-based overrides of async methods when subclassing 'Stream' 497 | # dotnet_diagnostic.CA1844.severity = suggestion 498 | # # CA1845: Use span-based 'string.Concat' 499 | # dotnet_diagnostic.CA1845.severity = suggestion 500 | # # CA1846: Prefer AsSpan over Substring 501 | # dotnet_diagnostic.CA1846.severity = suggestion 502 | # # CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters 503 | # dotnet_diagnostic.CA1847.severity = suggestion 504 | # # CA1852: Seal internal types 505 | # dotnet_diagnostic.CA1852.severity = suggestion 506 | # # CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method 507 | # dotnet_diagnostic.CA1854.severity = suggestion 508 | # # CA1855: Prefer 'Clear' over 'Fill' 509 | # dotnet_diagnostic.CA1855.severity = suggestion 510 | # # CA1856: Incorrect usage of ConstantExpected attribute 511 | # dotnet_diagnostic.CA1856.severity = suggestion 512 | # # CA1857: A constant is expected for the parameter 513 | # dotnet_diagnostic.CA1857.severity = suggestion 514 | # # CA1858: Use 'StartsWith' instead of 'IndexOf' 515 | # dotnet_diagnostic.CA1858.severity = suggestion 516 | # # CA2007: Consider calling ConfigureAwait on the awaited task 517 | # dotnet_diagnostic.CA2007.severity = suggestion 518 | # # CA2008: Do not create tasks without passing a TaskScheduler 519 | # dotnet_diagnostic.CA2008.severity = suggestion 520 | # # CA2012: Use ValueTask correctly 521 | # dotnet_diagnostic.CA2012.severity = suggestion 522 | # # CA2249: Use string.Contains instead of string.IndexOf to improve readability. 523 | # dotnet_diagnostic.CA2249.severity = suggestion 524 | # # IDE0005: Remove unnecessary usings 525 | # dotnet_diagnostic.IDE0005.severity = suggestion 526 | # # IDE0020: Use pattern matching to avoid is check followed by a cast (with variable) 527 | # dotnet_diagnostic.IDE0020.severity = suggestion 528 | # # IDE0029: Use coalesce expression (non-nullable types) 529 | # dotnet_diagnostic.IDE0029.severity = suggestion 530 | # # IDE0030: Use coalesce expression (nullable types) 531 | # dotnet_diagnostic.IDE0030.severity = suggestion 532 | # # IDE0031: Use null propagation 533 | # dotnet_diagnostic.IDE0031.severity = suggestion 534 | # # IDE0038: Use pattern matching to avoid is check followed by a cast (without variable) 535 | # dotnet_diagnostic.IDE0038.severity = suggestion 536 | # # IDE0044: Make field readonly 537 | # dotnet_diagnostic.IDE0044.severity = suggestion 538 | # # IDE0051: Remove unused private members 539 | # dotnet_diagnostic.IDE0051.severity = suggestion 540 | # # IDE0059: Unnecessary assignment to a value 541 | # dotnet_diagnostic.IDE0059.severity = suggestion 542 | # # IDE0060: Remove unused parameters 543 | # dotnet_diagnostic.IDE0060.severity = suggestion 544 | # # IDE0062: Make local function static 545 | # dotnet_diagnostic.IDE0062.severity = suggestion 546 | # # IDE0200: Lambda expression can be removed 547 | # dotnet_diagnostic.IDE0200.severity = suggestion 548 | # 549 | # # CA2016: Forward the 'CancellationToken' parameter to methods that take one 550 | # dotnet_diagnostic.CA2016.severity = suggestion 551 | # 552 | # # Defaults for content in the shared src/ and shared runtime dir 553 | # 554 | # [{**/Shared/runtime/**.{cs,vb},src/Shared/test/Shared.Tests/runtime/**.{cs,vb},**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}] 555 | # # CA1822: Make member static 556 | # dotnet_diagnostic.CA1822.severity = silent 557 | # # IDE0011: Use braces 558 | # dotnet_diagnostic.IDE0011.severity = silent 559 | # # IDE0055: Fix formatting 560 | # dotnet_diagnostic.IDE0055.severity = silent 561 | # # IDE0060: Remove unused parameters 562 | # dotnet_diagnostic.IDE0060.severity = silent 563 | # # IDE0062: Make local function static 564 | # dotnet_diagnostic.IDE0062.severity = silent 565 | # # IDE0161: Convert to file-scoped namespace 566 | # dotnet_diagnostic.IDE0161.severity = silent 567 | # 568 | # [{**/Shared/**.cs,**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}] 569 | # # IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included. 570 | # dotnet_diagnostic.IDE0005.severity = silent -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: dotnet-unit-test 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, macos-latest, windows-2022] 13 | fail-fast: false 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: 7.0.306 # https://github.com/microsoft/testfx/issues/1733 20 | - name: Build and Test 21 | run: | 22 | cd .NET 23 | dotnet restore 24 | dotnet build --no-restore 25 | dotnet test --no-build --verbosity normal -------------------------------------------------------------------------------- /.github/workflows/nuget-publish.yml: -------------------------------------------------------------------------------- 1 | name: publish-nuget-package 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: 7.0.306 # https://github.com/microsoft/testfx/issues/1733 20 | - name: Pack and Publish 21 | env: 22 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} 23 | run: | 24 | cd .NET 25 | dotnet restore 26 | dotnet pack -c Release -o out ./OneShotInjection 27 | dotnet nuget push ./out/*.nupkg --api-key $NUGET_API_KEY --source https://api.nuget.org/v3/index.json 28 | -------------------------------------------------------------------------------- /.github/workflows/release-upm.yml: -------------------------------------------------------------------------------- 1 | name: Publish UPM Package 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'Packages/**/package.json' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | upm-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Create Release for OpenUPM 17 | id: create_release 18 | uses: quabug/create-upm-release@v2 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | with: 22 | target: main 23 | upm_tag_prefix: v 24 | upm_package_path: Packages/com.quabug.one-shot-injection 25 | create_unitypackage: true 26 | unitypackage_name: OneShot 27 | -------------------------------------------------------------------------------- /.github/workflows/unity-test.yml: -------------------------------------------------------------------------------- 1 | name: unity-test 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | backend: 15 | - Mono2x 16 | - IL2CPP 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/cache@v3 20 | with: 21 | path: | 22 | Library 23 | CodeCoverage 24 | key: LibraryAndCoverage 25 | - uses: game-ci/unity-test-runner@v2 26 | id: unity-test 27 | env: 28 | UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} 29 | with: 30 | customParameters: -scriptingBackend ${{ matrix.backend }} -testCategory "!benchmark" 31 | projectPath: . 32 | githubToken: ${{ secrets.GITHUB_TOKEN }} 33 | coverageOptions: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;pathFilters:+**/Packages/**' 34 | - uses: actions/upload-artifact@v3 35 | if: always() 36 | with: 37 | name: Coverage results for ${{ matrix.backend }} 38 | path: ${{ steps.unity-test.outputs.coveragePath }} 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | /.idea 22 | 23 | # CI 24 | /artifacts 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | 50 | # Unity3D generated meta files 51 | *.pidb.meta 52 | *.pdb.meta 53 | *.mdb.meta 54 | 55 | # Unity3D generated file on crash reports 56 | sysinfo.txt 57 | 58 | # Builds 59 | *.apk 60 | *.unitypackage 61 | 62 | # Crashlytics generated file 63 | crashlytics-build.properties 64 | 65 | InitTestScene*.unity 66 | InitTestScene*.unity.meta 67 | 68 | /UserSettings 69 | 70 | obj 71 | bin 72 | 73 | !/.NET/** 74 | -------------------------------------------------------------------------------- /Assets/Benchmark.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 92b86638f1ccc4e06a05144f1a661bd9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Benchmark/Benchmark.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Benchmark", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner", 7 | "Unity.PerformanceTesting" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": true, 13 | "precompiledReferences": [ 14 | "nunit.framework.dll" 15 | ], 16 | "autoReferenced": false, 17 | "defineConstraints": [ 18 | "UNITY_INCLUDE_TESTS" 19 | ], 20 | "versionDefines": [], 21 | "noEngineReferences": false 22 | } -------------------------------------------------------------------------------- /Assets/Benchmark/Benchmark.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79c0ad547866942c88802f0b51fa2850 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Benchmark/BenchmarkCreateInstance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | using NUnit.Framework; 6 | using Unity.PerformanceTesting; 7 | using UnityEngine; 8 | 9 | [Category("benchmark")] 10 | public class BenchmarkCreateInstance 11 | { 12 | class Empty {} 13 | 14 | class Complex 15 | { 16 | public int I; 17 | public long L; 18 | public double D; 19 | public string S; 20 | public Matrix4x4 M; 21 | 22 | public Complex(int i, long l, double d, string s, Matrix4x4 m) 23 | { 24 | I = i; 25 | L = l; 26 | D = d; 27 | S = s; 28 | M = m; 29 | } 30 | } 31 | 32 | [Test, Performance] 33 | public void create_empty_instance() 34 | { 35 | var type = typeof(Empty); 36 | var ci = type.GetConstructors()[0]; 37 | var expression = Compile(ci); 38 | 39 | Measure.Method(() => new Empty()) 40 | .GC() 41 | .SampleGroup("new") 42 | .WarmupCount(1) 43 | .IterationsPerMeasurement(10000) 44 | .MeasurementCount(5) 45 | .Run(); 46 | 47 | Measure.Method(() => Activator.CreateInstance(type)) 48 | .GC() 49 | .SampleGroup("Activator.CreateInstance") 50 | .WarmupCount(1) 51 | .IterationsPerMeasurement(10000) 52 | .MeasurementCount(5) 53 | .Run(); 54 | 55 | Measure.Method(() => ci.Invoke(Array.Empty())) 56 | .GC() 57 | .SampleGroup("Constructor.Invoke") 58 | .WarmupCount(1) 59 | .IterationsPerMeasurement(10000) 60 | .MeasurementCount(5) 61 | .Run(); 62 | 63 | Measure.Method(() => 64 | { 65 | var instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); 66 | ci.Invoke(instance, Array.Empty()); 67 | }) 68 | .GC() 69 | .SampleGroup("Constructor.Invoke with instance") 70 | .WarmupCount(1) 71 | .IterationsPerMeasurement(10000) 72 | .MeasurementCount(5) 73 | .Run(); 74 | 75 | Measure.Method(() => expression(Array.Empty())) 76 | .GC() 77 | .SampleGroup("Expression") 78 | .WarmupCount(1) 79 | .IterationsPerMeasurement(10000) 80 | .MeasurementCount(5) 81 | .Run(); 82 | } 83 | 84 | [Test, Performance] 85 | public void create_complex_instance() 86 | { 87 | var type = typeof(Complex); 88 | var ci = type.GetConstructors()[0]; 89 | var expression = Compile(ci); 90 | var args = new object[] { 123, 234L, 111.111, "fjklfd", Matrix4x4.identity }; 91 | 92 | Measure.Method(() => new Complex(123, 234L, 111.111, "fjklfd", Matrix4x4.identity)) 93 | .GC() 94 | .SampleGroup("new") 95 | .WarmupCount(1) 96 | .IterationsPerMeasurement(10000) 97 | .MeasurementCount(5) 98 | .Run(); 99 | 100 | Measure.Method(() => Activator.CreateInstance(type, args)) 101 | .GC() 102 | .SampleGroup("Activator.CreateInstance") 103 | .WarmupCount(1) 104 | .IterationsPerMeasurement(10000) 105 | .MeasurementCount(5) 106 | .Run(); 107 | 108 | Measure.Method(() => ci.Invoke(args)) 109 | .GC() 110 | .SampleGroup("Constructor.Invoke") 111 | .WarmupCount(1) 112 | .IterationsPerMeasurement(10000) 113 | .MeasurementCount(5) 114 | .Run(); 115 | 116 | Measure.Method(() => 117 | { 118 | var instance = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); 119 | ci.Invoke(instance, args); 120 | }) 121 | .GC() 122 | .SampleGroup("Constructor.Invoke with instance") 123 | .WarmupCount(1) 124 | .IterationsPerMeasurement(10000) 125 | .MeasurementCount(5) 126 | .Run(); 127 | 128 | Measure.Method(() => expression(args)) 129 | .GC() 130 | .SampleGroup("Expression") 131 | .WarmupCount(1) 132 | .IterationsPerMeasurement(10000) 133 | .MeasurementCount(5) 134 | .Run(); 135 | } 136 | 137 | Func Compile(ConstructorInfo ci) 138 | { 139 | var @params = Expression.Parameter(typeof(object[])); 140 | var args = ci.GetParameters().Select((parameter, index) => Expression.Convert( 141 | Expression.ArrayIndex(@params, Expression.Constant(index)), 142 | parameter.ParameterType) 143 | ).Cast().ToArray(); 144 | var @new = Expression.New(ci, args); 145 | var lambda = Expression.Lambda(typeof(Func), Expression.Convert(@new, typeof(object)), @params); 146 | return (Func) lambda.Compile(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Assets/Benchmark/BenchmarkCreateInstance.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1234ca81275a459fad0de6947d7e390 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/FooInstaller.cs: -------------------------------------------------------------------------------- 1 | using OneShot; 2 | using UnityEngine; 3 | 4 | public class Foo {} 5 | public class FooInstaller : MonoBehaviour, IInstaller 6 | { 7 | public void Install(Container container) 8 | { 9 | container.RegisterInstance(123).AsSelf(); 10 | container.RegisterInstance(123f).AsSelf(); 11 | container.Register().Transient().AsSelf(); 12 | container.Register().Singleton().AsSelf(); 13 | container.Register().Scoped().AsSelf(); 14 | container.Register().Scoped().AsSelf(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Assets/FooInstaller.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dcc3a8671cab12e42b8bf49149e61973 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Sample.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.3731193, g: 0.38073996, b: 0.35872698, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 12 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: 0 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_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_LightingSettings: {fileID: 0} 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | maxJobWorkers: 0 122 | preserveTilesOutsideBounds: 0 123 | debug: 124 | m_Flags: 0 125 | m_NavMeshData: {fileID: 0} 126 | --- !u!1 &1477892229 127 | GameObject: 128 | m_ObjectHideFlags: 0 129 | m_CorrespondingSourceObject: {fileID: 0} 130 | m_PrefabInstance: {fileID: 0} 131 | m_PrefabAsset: {fileID: 0} 132 | serializedVersion: 6 133 | m_Component: 134 | - component: {fileID: 1477892230} 135 | - component: {fileID: 1477892231} 136 | m_Layer: 0 137 | m_Name: GameObject 138 | m_TagString: Untagged 139 | m_Icon: {fileID: 0} 140 | m_NavMeshLayer: 0 141 | m_StaticEditorFlags: 0 142 | m_IsActive: 1 143 | --- !u!4 &1477892230 144 | Transform: 145 | m_ObjectHideFlags: 0 146 | m_CorrespondingSourceObject: {fileID: 0} 147 | m_PrefabInstance: {fileID: 0} 148 | m_PrefabAsset: {fileID: 0} 149 | m_GameObject: {fileID: 1477892229} 150 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 151 | m_LocalPosition: {x: 0, y: 0, z: 0} 152 | m_LocalScale: {x: 1, y: 1, z: 1} 153 | m_ConstrainProportionsScale: 0 154 | m_Children: [] 155 | m_Father: {fileID: 1674272805} 156 | m_RootOrder: 0 157 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 158 | --- !u!114 &1477892231 159 | MonoBehaviour: 160 | m_ObjectHideFlags: 0 161 | m_CorrespondingSourceObject: {fileID: 0} 162 | m_PrefabInstance: {fileID: 0} 163 | m_PrefabAsset: {fileID: 0} 164 | m_GameObject: {fileID: 1477892229} 165 | m_Enabled: 1 166 | m_EditorHideFlags: 0 167 | m_Script: {fileID: 11500000, guid: dcc3a8671cab12e42b8bf49149e61973, type: 3} 168 | m_Name: 169 | m_EditorClassIdentifier: 170 | --- !u!1 &1674272802 171 | GameObject: 172 | m_ObjectHideFlags: 0 173 | m_CorrespondingSourceObject: {fileID: 0} 174 | m_PrefabInstance: {fileID: 0} 175 | m_PrefabAsset: {fileID: 0} 176 | serializedVersion: 6 177 | m_Component: 178 | - component: {fileID: 1674272805} 179 | - component: {fileID: 1674272804} 180 | - component: {fileID: 1674272803} 181 | m_Layer: 0 182 | m_Name: GameObject 183 | m_TagString: Untagged 184 | m_Icon: {fileID: 0} 185 | m_NavMeshLayer: 0 186 | m_StaticEditorFlags: 0 187 | m_IsActive: 1 188 | --- !u!114 &1674272803 189 | MonoBehaviour: 190 | m_ObjectHideFlags: 0 191 | m_CorrespondingSourceObject: {fileID: 0} 192 | m_PrefabInstance: {fileID: 0} 193 | m_PrefabAsset: {fileID: 0} 194 | m_GameObject: {fileID: 1674272802} 195 | m_Enabled: 1 196 | m_EditorHideFlags: 0 197 | m_Script: {fileID: 11500000, guid: dcc3a8671cab12e42b8bf49149e61973, type: 3} 198 | m_Name: 199 | m_EditorClassIdentifier: 200 | --- !u!114 &1674272804 201 | MonoBehaviour: 202 | m_ObjectHideFlags: 0 203 | m_CorrespondingSourceObject: {fileID: 0} 204 | m_PrefabInstance: {fileID: 0} 205 | m_PrefabAsset: {fileID: 0} 206 | m_GameObject: {fileID: 1674272802} 207 | m_Enabled: 1 208 | m_EditorHideFlags: 0 209 | m_Script: {fileID: 11500000, guid: 216e911c2394dac4cab7c7e2c1dbae32, type: 3} 210 | m_Name: 211 | m_EditorClassIdentifier: 212 | InjectPhase: 1 213 | _injectableOnly: 0 214 | _recursiveDepth: -1 215 | _stopOnInactiveObject: 0 216 | --- !u!4 &1674272805 217 | Transform: 218 | m_ObjectHideFlags: 0 219 | m_CorrespondingSourceObject: {fileID: 0} 220 | m_PrefabInstance: {fileID: 0} 221 | m_PrefabAsset: {fileID: 0} 222 | m_GameObject: {fileID: 1674272802} 223 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 224 | m_LocalPosition: {x: 0, y: 0, z: 0} 225 | m_LocalScale: {x: 1, y: 1, z: 1} 226 | m_ConstrainProportionsScale: 0 227 | m_Children: 228 | - {fileID: 1477892230} 229 | m_Father: {fileID: 0} 230 | m_RootOrder: 0 231 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 232 | -------------------------------------------------------------------------------- /Assets/Sample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4580a101583ce8d49be96328d67bf1d0 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 29ec75649fcadf1468df51928387ce85 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Tests/Fixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OneShot.Test 4 | { 5 | internal interface InterfaceA 6 | { 7 | } 8 | 9 | internal class TypeA : InterfaceA 10 | { 11 | } 12 | 13 | internal class DefaultConstructor 14 | { 15 | public readonly TypeA TypeA; 16 | public DefaultConstructor(TypeA typeA) => TypeA = typeA; 17 | public int GetIntValue() => 100; 18 | } 19 | 20 | internal class InjectConstructor 21 | { 22 | public readonly TypeA TypeA; 23 | 24 | [Inject] 25 | public InjectConstructor(TypeA typeA) => TypeA = typeA; 26 | 27 | public InjectConstructor(DefaultConstructor defaultConstructor) => TypeA = null; 28 | } 29 | 30 | internal class ConstructorWithDefaultParameter 31 | { 32 | public readonly TypeA TypeA; 33 | public readonly int IntValue = 0; 34 | 35 | public ConstructorWithDefaultParameter(TypeA typeA, int intValue = 10) 36 | { 37 | TypeA = typeA; 38 | IntValue = intValue; 39 | } 40 | } 41 | 42 | internal class ComplexClass 43 | { 44 | public readonly TypeA A; 45 | public readonly InterfaceA B; 46 | public readonly InjectConstructor C; 47 | public readonly float D; 48 | public readonly ConstructorWithDefaultParameter E; 49 | public readonly Func GetIntValue; 50 | 51 | public ComplexClass(TypeA a, InterfaceA b, InjectConstructor c, float d = 22, 52 | ConstructorWithDefaultParameter e = null, Func getIntValue = null) 53 | { 54 | A = a; 55 | B = b; 56 | C = c; 57 | D = d; 58 | E = e; 59 | GetIntValue = getIntValue; 60 | } 61 | } 62 | 63 | internal class Disposable : IDisposable 64 | { 65 | public int DisposedCount = 0; 66 | public void Dispose() => DisposedCount++; 67 | } 68 | 69 | internal class InjectInt 70 | { 71 | public int Value; 72 | public InjectInt(int value) => Value = value; 73 | } 74 | } -------------------------------------------------------------------------------- /Assets/Tests/Fixture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: adae12e9dd4684419bd2ebda3d021474 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Tests/TestCircularCheck.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace OneShot.Test 4 | { 5 | public class TestCircularCheck 6 | { 7 | class A 8 | { 9 | public A(B b) 10 | { 11 | } 12 | } 13 | 14 | class B 15 | { 16 | public B(A a) 17 | { 18 | } 19 | } 20 | 21 | [Test] 22 | public void should_throw_on_directly_circular_dependency() 23 | { 24 | var container = new Container(); 25 | container.Register().AsSelf(); 26 | container.Register().AsSelf(); 27 | Assert.Catch(() => container.Resolve()); 28 | Assert.Catch(() => container.Resolve()); 29 | } 30 | 31 | private class C 32 | { 33 | public C(D _) 34 | { 35 | } 36 | } 37 | 38 | private class D 39 | { 40 | public D(E _) 41 | { 42 | } 43 | } 44 | 45 | private class E 46 | { 47 | public E(C _) 48 | { 49 | } 50 | } 51 | 52 | [Test] 53 | public void should_throw_on_indirectly_circular_dependency() 54 | { 55 | var container = new Container(); 56 | container.Register().AsSelf(); 57 | container.Register().AsSelf(); 58 | container.Register().AsSelf(); 59 | Assert.Catch(() => container.Resolve()); 60 | Assert.Catch(() => container.Resolve()); 61 | Assert.Catch(() => container.Resolve()); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Assets/Tests/TestCircularCheck.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66df5e32433a4481ca92b55bc37739f9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Tests/TestGeneric.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using NUnit.Framework; 4 | 5 | namespace OneShot.Test 6 | { 7 | public class TestGeneric 8 | { 9 | class Generic {} 10 | class Generic {} 11 | 12 | private static Type[] _genericArguments = { 13 | typeof(Generic), typeof(Generic), typeof(Generic>), typeof(Generic>>), 14 | typeof(Generic), typeof(Generic, Generic>), typeof(Generic>) 15 | }; 16 | 17 | [Test, TestCaseSource(nameof(_genericArguments))] 18 | public void should_make_instance_of_generic(Type type) 19 | { 20 | var container = new Container(); 21 | container.Register(typeof(Generic<>), (_, t) => Activator.CreateInstance(typeof(Generic<>).MakeGenericType(t.GetGenericArguments()))).As(typeof(Generic<>)); 22 | container.Register(typeof(Generic<,>), (_, t) => Activator.CreateInstance(typeof(Generic<,>).MakeGenericType(t.GetGenericArguments()))).As(typeof(Generic<,>)); 23 | Assert.That(container.Resolve(type), Is.TypeOf(type)); 24 | } 25 | 26 | interface Label : ILabel {} 27 | 28 | [Test, TestCaseSource(nameof(_genericArguments))] 29 | public void should_make_instance_of_generic_with_label(Type type) 30 | { 31 | var container = new Container(); 32 | container.Register(typeof(Generic<>), (_, t) => Activator.CreateInstance(typeof(Generic<>).MakeGenericType(t.GetGenericArguments()))).As(typeof(Generic<>), typeof(Label<>)); 33 | container.Register(typeof(Generic<,>), (_, t) => Activator.CreateInstance(typeof(Generic<,>).MakeGenericType(t.GetGenericArguments()))).As(typeof(Generic<,>), typeof(Label<>)); 34 | Assert.Catch(() => container.Resolve(type)); 35 | Assert.That(container.Resolve(type, typeof(Label<>)), Is.TypeOf(type)); 36 | } 37 | 38 | [Test] 39 | public void should_make_instance_of_concrete_generic() 40 | { 41 | var container = new Container(); 42 | var instance = new Generic(); 43 | container.RegisterInstance(instance).As>(); 44 | Assert.That(container.Resolve>(), Is.SameAs(instance)); 45 | } 46 | 47 | private static Lazy CreateLazy(Container container, Type _) 48 | { 49 | return new Lazy(() => container.Resolve()); 50 | } 51 | 52 | [Test] 53 | public void should_register_and_resolve_generic_type_by_method_name() 54 | { 55 | var container = new Container(); 56 | var creator = GetType().GetMethod(nameof(CreateLazy), BindingFlags.Static | BindingFlags.NonPublic); 57 | container.RegisterGeneric(typeof(Lazy<>), creator).With(123).AsSelf(); 58 | Assert.That(container.Resolve>().Value, Is.EqualTo(123)); 59 | } 60 | 61 | private static Generic CreateGeneric(Container container, Type _) 62 | { 63 | return new Generic(); 64 | } 65 | 66 | private static void InvalidReturnCreator(Container container, Type _) 67 | { 68 | } 69 | 70 | private static Generic InvalidParameterCreator(Container container) 71 | { 72 | return new Generic(); 73 | } 74 | 75 | [Test] 76 | public void should_register_and_resolve_generic_with_multiple_type_parameters_by_method_name() 77 | { 78 | var container = new Container(); 79 | var creator = GetType().GetMethod(nameof(CreateGeneric), BindingFlags.Static | BindingFlags.NonPublic); 80 | container.RegisterGeneric(typeof(Generic<,>), creator).AsSelf(); 81 | var instance = container.Resolve>(); 82 | } 83 | 84 | [Test] 85 | public void should_throw_exception_if_creator_is_not_valid() 86 | { 87 | var container = new Container(); 88 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<,>), null).AsSelf()); 89 | 90 | var lazyCreator = GetType().GetMethod(nameof(CreateLazy), BindingFlags.Static | BindingFlags.NonPublic); 91 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<>), lazyCreator).AsSelf()); 92 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<,>), lazyCreator).AsSelf()); 93 | 94 | var genericCreator = GetType().GetMethod(nameof(CreateGeneric), BindingFlags.Static | BindingFlags.NonPublic); 95 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<>), genericCreator).AsSelf()); 96 | 97 | var invalidReturnCreator = GetType().GetMethod(nameof(InvalidReturnCreator), BindingFlags.Static | BindingFlags.NonPublic); 98 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<,>), invalidReturnCreator).AsSelf()); 99 | 100 | var invalidParameterCreator = GetType().GetMethod(nameof(InvalidParameterCreator), BindingFlags.Static | BindingFlags.NonPublic); 101 | Assert.Throws(() => container.RegisterGeneric(typeof(Generic<,>), invalidParameterCreator).AsSelf()); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Assets/Tests/TestGeneric.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b2dff33d8ee414088c3d5f58c64202d 3 | timeCreated: 1664279846 -------------------------------------------------------------------------------- /Assets/Tests/TestLabel.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace OneShot.Test 4 | { 5 | public class TestLabel 6 | { 7 | class Foo {} 8 | interface LabelFoo : ILabel {} 9 | interface LabelAny : ILabel {} 10 | 11 | class Bar 12 | { 13 | public Foo LabeledFoo; 14 | public Foo Foo; 15 | public Foo AnyLabeledFoo; 16 | 17 | [Inject(typeof(LabelAny<>))] public Foo AnyProperty { get; private set; } 18 | [Inject(typeof(LabelFoo))] public Foo FooField; 19 | 20 | public Foo MethodFoo; 21 | [Inject] public void Inject([Inject(typeof(LabelFoo))] Foo foo) => MethodFoo = foo; 22 | 23 | public Bar([Inject(typeof(LabelFoo))] Foo labeledFoo, Foo foo, [Inject(typeof(LabelAny<>))] Foo anyLabeledFoo) 24 | { 25 | LabeledFoo = labeledFoo; 26 | Foo = foo; 27 | AnyLabeledFoo = anyLabeledFoo; 28 | } 29 | } 30 | 31 | [Test] 32 | public void should_make_instance_by_label() 33 | { 34 | var container = new Container(); 35 | 36 | var foo = new Foo(); 37 | var labeledFoo = new Foo(); 38 | var anyLabeledFoo = new Foo(); 39 | 40 | container.RegisterInstance(foo).AsSelf(); 41 | container.RegisterInstance(labeledFoo).AsSelf(typeof(LabelFoo)); 42 | container.RegisterInstance(anyLabeledFoo).AsSelf(typeof(LabelAny<>)); 43 | 44 | Assert.That(container.Resolve(), Is.SameAs(foo)); 45 | Assert.That(container.Resolve(typeof(LabelFoo)), Is.SameAs(labeledFoo)); 46 | Assert.That(container.Resolve(typeof(LabelAny<>)), Is.SameAs(anyLabeledFoo)); 47 | 48 | container.Register().AsSelf(); 49 | var bar = container.Resolve(); 50 | Assert.That(bar.Foo, Is.SameAs(foo)); 51 | Assert.That(bar.LabeledFoo, Is.SameAs(labeledFoo)); 52 | Assert.That(bar.AnyLabeledFoo, Is.SameAs(anyLabeledFoo)); 53 | } 54 | 55 | [Test] 56 | public void should_make_instance_by_labeled_additional_instances() 57 | { 58 | var container = new Container(); 59 | var foo = new Foo(); 60 | var labeledFoo = new Foo(); 61 | var anyLabeledFoo = new Foo(); 62 | 63 | container.Register().With((foo, null), (labeledFoo, typeof(LabelFoo)), (anyLabeledFoo, typeof(LabelAny<>))).AsSelf(); 64 | var bar = container.Resolve(); 65 | Assert.That(bar.Foo, Is.SameAs(foo)); 66 | Assert.That(bar.LabeledFoo, Is.SameAs(labeledFoo)); 67 | Assert.That(bar.AnyLabeledFoo, Is.SameAs(anyLabeledFoo)); 68 | } 69 | 70 | [Test] 71 | public void should_inject_labeled_instances() 72 | { 73 | var container = new Container(); 74 | 75 | var foo = new Foo(); 76 | var labeledFoo = new Foo(); 77 | var anyLabeledFoo = new Foo(); 78 | 79 | container.RegisterInstance(foo).AsSelf(); 80 | container.RegisterInstance(labeledFoo).AsSelf(typeof(LabelFoo)); 81 | container.RegisterInstance(anyLabeledFoo).AsSelf(typeof(LabelAny<>)); 82 | 83 | container.Register().AsSelf(); 84 | var bar = container.Resolve(); 85 | Assert.That(bar.MethodFoo, Is.Null); 86 | Assert.That(bar.AnyProperty, Is.Null); 87 | Assert.That(bar.FooField, Is.Null); 88 | container.InjectAll(bar); 89 | Assert.That(bar.MethodFoo, Is.SameAs(labeledFoo)); 90 | Assert.That(bar.AnyProperty, Is.SameAs(anyLabeledFoo)); 91 | Assert.That(bar.FooField, Is.SameAs(labeledFoo)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Assets/Tests/TestLabel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2010bcf57c5a4bc7ab6eee4ef23540fc 3 | timeCreated: 1661402499 -------------------------------------------------------------------------------- /Assets/Tests/TestLifetime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace OneShot.Test 5 | { 6 | public class TestLifetime 7 | { 8 | [Test] 9 | public void should_resolve_instance() 10 | { 11 | var container = new Container(); 12 | var instance = new TypeA(); 13 | container.RegisterInstance(instance).AsSelf(); 14 | Assert.AreSame(instance, container.Resolve()); 15 | } 16 | 17 | [Test] 18 | public void should_resolve_singleton() 19 | { 20 | var container = new Container(); 21 | container.Register().Singleton().AsSelf(); 22 | Assert.AreSame(container.Resolve(), container.Resolve()); 23 | } 24 | 25 | [Test] 26 | public void should_resolve_singleton_func() 27 | { 28 | var container = new Container(); 29 | Func createTypeA = (c, t) => new TypeA(); 30 | container.Register(createTypeA).Singleton().AsSelf(); 31 | Assert.AreSame(container.Resolve(), container.Resolve()); 32 | } 33 | 34 | [Test] 35 | public void should_resolve_transient() 36 | { 37 | var container = new Container(); 38 | container.Register().AsSelf(); 39 | Assert.AreNotSame(container.Resolve(), container.Resolve()); 40 | } 41 | 42 | [Test] 43 | public void should_resolve_scoped() 44 | { 45 | var container = new Container(); 46 | container.Register().Scoped().AsSelf(); 47 | Assert.AreSame(container.Resolve(), container.Resolve()); 48 | var childContainer = container.CreateChildContainer(); 49 | Assert.AreNotSame(container.Resolve(), childContainer.Resolve()); 50 | Assert.AreSame(childContainer.Resolve(), childContainer.Resolve()); 51 | var grandChildContainer = childContainer.CreateChildContainer(); 52 | Assert.AreNotSame(childContainer.Resolve(), grandChildContainer.Resolve()); 53 | Assert.AreSame(grandChildContainer.Resolve(), grandChildContainer.Resolve()); 54 | } 55 | 56 | [Test] 57 | public void should_resolve_types_in_parent_container() 58 | { 59 | var container = new Container(); 60 | var instance = new TypeA(); 61 | container.RegisterInstance(instance).AsSelf(); 62 | 63 | var child1 = container.CreateChildContainer(); 64 | child1.Resolve(); 65 | child1.Register().Singleton().AsSelf(); 66 | Assert.AreSame(child1.Resolve(), child1.Resolve()); 67 | Assert.AreSame(instance, child1.Resolve().TypeA); 68 | 69 | var child2 = container.CreateChildContainer(); 70 | child2.Resolve(); 71 | child2.Register().AsSelf(); 72 | Assert.AreNotSame(child2.Resolve(), child2.Resolve()); 73 | Assert.AreSame(instance, child2.Resolve().TypeA); 74 | } 75 | 76 | [Test] 77 | public void should_dispose_container() 78 | { 79 | var container = new Container(); 80 | container.RegisterInstance(10).AsSelf(); 81 | container.Resolve(); 82 | container.Dispose(); 83 | Assert.Catch(() => container.Resolve()); 84 | } 85 | 86 | [Test] 87 | public void should_dispose_container_hierarchy() 88 | { 89 | var container = new Container(); 90 | container.RegisterInstance(10).AsSelf(); 91 | var child1 = container.CreateChildContainer(); 92 | var child11 = child1.CreateChildContainer(); 93 | var child12 = child1.CreateChildContainer(); 94 | var child121 = child12.CreateChildContainer(); 95 | var child122 = child12.CreateChildContainer(); 96 | Assert.AreEqual(10, child122.Resolve()); 97 | var child2 = container.CreateChildContainer(); 98 | child1.Dispose(); 99 | Assert.Catch(() => child1.Resolve()); 100 | Assert.Catch(() => child11.Resolve()); 101 | Assert.Catch(() => child12.Resolve()); 102 | Assert.Catch(() => child121.Resolve()); 103 | Assert.Catch(() => child122.Resolve()); 104 | Assert.AreEqual(10, child2.Resolve()); 105 | } 106 | 107 | [Test] 108 | public void should_dispose_transient_instances_of_container() 109 | { 110 | var container = new Container(); 111 | var childContainer = container.CreateChildContainer(); 112 | container.Register().AsSelf(); 113 | var disposable1 = container.Resolve(); 114 | var disposable2 = container.Resolve(); 115 | var childDisposable = childContainer.Resolve(); 116 | 117 | Assert.AreNotSame(disposable1, disposable2); 118 | Assert.AreNotSame(disposable1, childDisposable); 119 | Assert.AreEqual(0, disposable1.DisposedCount); 120 | Assert.AreEqual(0, disposable2.DisposedCount); 121 | Assert.AreEqual(0, childDisposable.DisposedCount); 122 | 123 | childContainer.Dispose(); 124 | Assert.AreEqual(0, disposable1.DisposedCount); 125 | Assert.AreEqual(0, disposable2.DisposedCount); 126 | Assert.AreEqual(1, childDisposable.DisposedCount); 127 | 128 | container.Dispose(); 129 | Assert.AreEqual(1, disposable1.DisposedCount); 130 | Assert.AreEqual(1, disposable2.DisposedCount); 131 | Assert.AreEqual(1, childDisposable.DisposedCount); 132 | } 133 | 134 | [Test] 135 | public void should_dispose_singleton_instances_of_container() 136 | { 137 | var container = new Container(); 138 | var childContainer = container.CreateChildContainer(); 139 | container.Register().Singleton().AsSelf(); 140 | var disposable1 = container.Resolve(); 141 | var disposable2 = container.Resolve(); 142 | var childDisposable = childContainer.Resolve(); 143 | 144 | Assert.AreSame(disposable1, disposable2); 145 | Assert.AreSame(disposable1, childDisposable); 146 | Assert.AreEqual(0, disposable1.DisposedCount); 147 | 148 | childContainer.Dispose(); 149 | Assert.AreEqual(0, disposable1.DisposedCount); 150 | 151 | container.Dispose(); 152 | Assert.AreEqual(1, disposable1.DisposedCount); 153 | } 154 | 155 | [Test] 156 | public void should_dispose_scope_instances_of_container() 157 | { 158 | var container = new Container(); 159 | var childContainer = container.CreateChildContainer(); 160 | container.Register().Scoped().AsSelf(); 161 | var disposable1 = container.Resolve(); 162 | var disposable2 = container.Resolve(); 163 | var childDisposable1 = childContainer.Resolve(); 164 | var childDisposable2 = childContainer.Resolve(); 165 | 166 | Assert.AreSame(disposable1, disposable2); 167 | Assert.AreSame(childDisposable1, childDisposable2); 168 | Assert.AreNotSame(disposable1, childDisposable1); 169 | 170 | Assert.AreEqual(0, disposable1.DisposedCount); 171 | Assert.AreEqual(0, childDisposable1.DisposedCount); 172 | 173 | childContainer.Dispose(); 174 | Assert.AreEqual(0, disposable1.DisposedCount); 175 | Assert.AreEqual(1, childDisposable1.DisposedCount); 176 | 177 | container.Dispose(); 178 | Assert.AreEqual(1, disposable1.DisposedCount); 179 | Assert.AreEqual(1, childDisposable1.DisposedCount); 180 | } 181 | 182 | [Test] 183 | public void should_dispose_all_instances_in_hierarchy_of_container() 184 | { 185 | var container = new Container(); 186 | var childContainer = container.CreateChildContainer(); 187 | container.Register().AsSelf(); 188 | var disposable1 = container.Resolve(); 189 | var disposable2 = container.Resolve(); 190 | var childDisposable = childContainer.Resolve(); 191 | 192 | container.Dispose(); 193 | Assert.AreEqual(1, disposable1.DisposedCount); 194 | Assert.AreEqual(1, disposable2.DisposedCount); 195 | Assert.AreEqual(1, childDisposable.DisposedCount); 196 | } 197 | 198 | [Test] 199 | public void should_create_singleton_instance_based_on_registered_container() 200 | { 201 | var container = new Container(); 202 | container.Register().Singleton().AsSelf(); 203 | container.RegisterInstance(123).AsSelf(); 204 | Assert.That(container.Resolve().Value, Is.EqualTo(123)); 205 | 206 | var subContainer = container.CreateChildContainer(); 207 | subContainer.RegisterInstance(234).AsSelf(); 208 | Assert.That(subContainer.Resolve().Value, Is.EqualTo(123)); 209 | } 210 | 211 | [Test] 212 | public void should_create_scoped_instance_based_on_resolved_container() 213 | { 214 | var container = new Container(); 215 | container.Register().Scoped().AsSelf(); 216 | container.RegisterInstance(123).AsSelf(); 217 | Assert.That(container.Resolve().Value, Is.EqualTo(123)); 218 | 219 | var subContainer = container.CreateChildContainer(); 220 | subContainer.RegisterInstance(234).AsSelf(); 221 | Assert.That(subContainer.Resolve().Value, Is.EqualTo(234)); 222 | } 223 | 224 | [Test] 225 | public void should_create_transient_instance_based_on_resolved_container() 226 | { 227 | var container = new Container(); 228 | container.Register().Transient().AsSelf(); 229 | container.RegisterInstance(123).AsSelf(); 230 | Assert.That(container.Resolve().Value, Is.EqualTo(123)); 231 | 232 | var subContainer = container.CreateChildContainer(); 233 | subContainer.RegisterInstance(234).AsSelf(); 234 | Assert.That(subContainer.Resolve().Value, Is.EqualTo(234)); 235 | } 236 | 237 | [Test] 238 | public void should_throw_on_register_disposable_transient_if_check_on() 239 | { 240 | var container = new Container { PreventDisposableTransient = true }; 241 | Assert.Catch(() => container.Register().AsSelf()); 242 | Assert.Catch(() => container.Register().AsInterfaces()); 243 | } 244 | 245 | [Test] 246 | public void should_not_throw_on_register_disposable_transient_if_check_off() 247 | { 248 | var container = new Container { PreventDisposableTransient = false }; 249 | container.Register().AsSelf(); 250 | container.Register().AsInterfaces(); 251 | } 252 | 253 | [Test] 254 | public void should_not_check_disposable_on_other_lifetime() 255 | { 256 | var container = new Container { PreventDisposableTransient = true }; 257 | container.Register().Singleton().AsSelf(); 258 | container.Register().Scoped().AsInterfaces(); 259 | } 260 | 261 | [Test] 262 | public void should_not_able_to_create_singleton_with_child_instance() 263 | { 264 | var container = new Container(); 265 | var child = container.CreateChildContainer(); 266 | container.Register().Singleton().AsSelf(); 267 | child.Register().Singleton().AsSelf(); 268 | Assert.Catch(() => child.Resolve()); 269 | } 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /Assets/Tests/TestLifetime.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ce07b155a4794b48ba2d3c55fd47928 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Tests/TestMultithread.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Threading; 6 | using NUnit.Framework; 7 | 8 | namespace OneShot.Test 9 | { 10 | public class TestMultiThread 11 | { 12 | long _threadCount = 100; 13 | private Type[] _types; 14 | 15 | [SetUp] 16 | public void SetUp() 17 | { 18 | _types = GetType().GetNestedTypes(BindingFlags.NonPublic).Where(type => !type.IsInterface).ToArray(); 19 | } 20 | // 21 | // [Test] 22 | // public void should_able_to_register_() 23 | // { 24 | // var container = new Container(); 25 | // container.Register().Singleton().AsSelf().AsBases().AsInterfaces(); 26 | // container.Register().Singleton().AsSelf().AsBases().AsInterfaces(); 27 | // container.Register().Singleton().AsSelf().AsBases().AsInterfaces(); 28 | // container.Register().Singleton().AsSelf().AsBases().AsInterfaces(); 29 | // container.Register().AsSelf().AsBases().AsInterfaces(); 30 | // container.Register().AsSelf().AsBases().AsInterfaces(); 31 | // container.Register().AsSelf().AsBases().AsInterfaces(); 32 | // container.Resolve(); 33 | // } 34 | 35 | [Test] 36 | public void should_able_to_register_and_resolve_on_different_thread() 37 | { 38 | ThreadPool.GetAvailableThreads(out var workerThreads, out var completionPortThreads); 39 | Console.WriteLine($"workers = {workerThreads}, ports = {completionPortThreads}"); 40 | var count = _threadCount; 41 | 42 | var root = new Container(); 43 | root.PreAllocateArgumentArrayOnRegister = true; 44 | 45 | for(var i = 0; i < count; i++) new Thread(Run) { Name = $"Thread{i + 1}" }.Start(root); 46 | 47 | while (Interlocked.Read(ref _threadCount) > 0) 48 | { 49 | Thread.Sleep(200); 50 | Console.WriteLine($"remained {Interlocked.Read(ref _threadCount)}"); 51 | } 52 | } 53 | 54 | void Run(object state) 55 | { 56 | try 57 | { 58 | var container = (Container)state; 59 | var rnd = new Random(); 60 | var time = rnd.Next(0, 10000); 61 | 62 | var shouldCreateContainer = rnd.Next(3) == 0; 63 | if (shouldCreateContainer) container = container.CreateChildContainer(); 64 | 65 | var watch = Stopwatch.StartNew(); 66 | while (watch.ElapsedMilliseconds < time) 67 | { 68 | var type = _types[rnd.Next(_types.Length)]; 69 | switch (rnd.Next(3)) 70 | { 71 | case 0: 72 | container.Register(type).Transient().AsSelf().AsBases().AsInterfaces(); 73 | break; 74 | case 1: 75 | container.Register(type).Singleton().AsSelf().AsBases().AsInterfaces(); 76 | break; 77 | case 2: 78 | container.Register(type).Scoped().AsSelf().AsBases().AsInterfaces(); 79 | break; 80 | } 81 | Thread.Sleep(rnd.Next(0, 100)); 82 | } 83 | 84 | time = rnd.Next(0, 10000); 85 | watch.Restart(); 86 | while (watch.ElapsedMilliseconds < time) 87 | { 88 | var type = _types[rnd.Next(_types.Length)]; 89 | try 90 | { 91 | Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: resolve {type}"); 92 | var instances = container.ResolveGroup(type).Append(container.Resolve(type)); 93 | foreach (var instance in instances) 94 | if (!type.IsInstanceOfType(instance)) 95 | throw new ApplicationException($"{instance} != {type}"); 96 | } 97 | catch (ArgumentException) 98 | { 99 | // ignore 100 | } 101 | Thread.Sleep(rnd.Next(0, 100)); 102 | } 103 | 104 | if (shouldCreateContainer) container.Dispose(); 105 | } 106 | finally 107 | { 108 | var count = Interlocked.Decrement(ref _threadCount); 109 | Console.WriteLine($"{Thread.CurrentThread.Name} count={count}"); 110 | } 111 | } 112 | 113 | interface IA {} 114 | interface IB {} 115 | interface IC {} 116 | class A : IA {} 117 | class B : IB {} 118 | class C : IC {} 119 | class D : IA, IB, IC {} 120 | class E : C, IA, IB {} 121 | class F : E {} 122 | class G : A, IC {} 123 | class H : B, IA {} 124 | 125 | class AB : IA 126 | { 127 | public AB(A a, B b) 128 | { 129 | if (!(a is A)) throw new ApplicationException(); 130 | if (!(b is B)) throw new ApplicationException(); 131 | } 132 | } 133 | 134 | class ABC 135 | { 136 | public ABC(A a, B b, C c) 137 | { 138 | if (!(a is A)) throw new ApplicationException(); 139 | if (!(b is B)) throw new ApplicationException(); 140 | if (!(c is C)) throw new ApplicationException(); 141 | } 142 | } 143 | 144 | class ABCD 145 | { 146 | public ABCD(A a, B b, C c, D d) 147 | { 148 | if (!(a is A)) throw new ApplicationException(); 149 | if (!(b is B)) throw new ApplicationException(); 150 | if (!(c is C)) throw new ApplicationException(); 151 | if (!(d is D)) throw new ApplicationException(); 152 | } 153 | } 154 | 155 | class BCD : IA 156 | { 157 | public BCD(B b, C c, D d) 158 | { 159 | if (!(b is B)) throw new ApplicationException(); 160 | if (!(c is C)) throw new ApplicationException(); 161 | if (!(d is D)) throw new ApplicationException(); 162 | } 163 | } 164 | 165 | class FG : IB, IC 166 | { 167 | public FG(F f, G g) 168 | { 169 | if (!(f is F)) throw new ApplicationException(); 170 | if (!(g is G)) throw new ApplicationException(); 171 | } 172 | } 173 | 174 | class CDEF : IB, IC 175 | { 176 | public CDEF(C c, D d, E e, F f) 177 | { 178 | if (!(c is C)) throw new ApplicationException(); 179 | if (!(d is D)) throw new ApplicationException(); 180 | if (!(e is E)) throw new ApplicationException(); 181 | if (!(f is F)) throw new ApplicationException(); 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /Assets/Tests/TestMultithread.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd36230df279c4da0b46217dd77b9c80 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Tests/TestOneShot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace OneShot.Test 5 | { 6 | public class TestOneShot 7 | { 8 | [Test] 9 | public void should_not_able_to_register_invalid_type() 10 | { 11 | var container = new Container(); 12 | Assert.Catch(() => container.Register()); 13 | Assert.Catch(() => container.Register().As()); 14 | } 15 | 16 | [Test] 17 | public void should_able_to_register_and_resolve_interface() 18 | { 19 | var container = new Container(); 20 | var instance = new TypeA(); 21 | container.RegisterInstance(instance).AsSelf().As(); 22 | Assert.AreSame(instance, container.Resolve()); 23 | } 24 | 25 | [Test] 26 | public void should_inject_by_default_constructor() 27 | { 28 | var container = new Container(); 29 | var instance = new TypeA(); 30 | container.RegisterInstance(instance).AsSelf(); 31 | container.Register().Singleton().AsSelf(); 32 | Assert.AreSame(instance, container.Resolve().TypeA); 33 | } 34 | 35 | [Test] 36 | public void should_inject_by_marked_constructor() 37 | { 38 | var container = new Container(); 39 | var instance = new TypeA(); 40 | container.RegisterInstance(instance).AsSelf(); 41 | container.Register().Singleton().AsSelf(); 42 | Assert.AreSame(instance, container.Resolve().TypeA); 43 | } 44 | 45 | [Test] 46 | public void should_inject_by_constructor_with_default_parameters() 47 | { 48 | var container = new Container(); 49 | var instance = new TypeA(); 50 | container.RegisterInstance(instance).AsSelf(); 51 | container.Register().Singleton().AsSelf(); 52 | Assert.AreSame(instance, container.Resolve().TypeA); 53 | Assert.AreEqual(10, container.Resolve().IntValue); 54 | } 55 | 56 | [Test] 57 | public void should_resolve_complex_type() 58 | { 59 | var container = new Container(); 60 | var typeA = new TypeA(); 61 | container.RegisterInstance(typeA).AsSelf().As(); 62 | container.Register().AsSelf(); 63 | container.Register().Singleton().AsSelf(); 64 | container.Register().Singleton().AsSelf(); 65 | container.Register>((c, t) => container.Resolve().GetIntValue).AsSelf(); 66 | container.Register().AsSelf(); 67 | var complex1 = container.Resolve(); 68 | Assert.AreSame(typeA, complex1.A); 69 | Assert.AreSame(typeA, complex1.B); 70 | Assert.AreSame(typeA, complex1.C.TypeA); 71 | Assert.AreSame(typeA, complex1.C.TypeA); 72 | Assert.AreEqual(22, complex1.D); 73 | Assert.AreSame(typeA, complex1.E.TypeA); 74 | Assert.AreEqual(10, complex1.E.IntValue); 75 | Assert.AreEqual(100, complex1.GetIntValue()); 76 | 77 | var complex2 = container.Resolve(); 78 | Assert.AreSame(typeA, complex2.A); 79 | Assert.AreSame(typeA, complex2.B); 80 | Assert.AreSame(typeA, complex2.C.TypeA); 81 | Assert.AreSame(typeA, complex2.C.TypeA); 82 | Assert.AreEqual(22, complex2.D); 83 | Assert.AreSame(typeA, complex2.E.TypeA); 84 | Assert.AreEqual(10, complex2.E.IntValue); 85 | Assert.AreEqual(100, complex2.GetIntValue()); 86 | 87 | Assert.AreNotSame(complex1.C, complex2.C); 88 | Assert.AreSame(complex1.E, complex2.E); 89 | } 90 | 91 | [Test] 92 | public void should_able_to_register_and_resolve_func() 93 | { 94 | var container = new Container(); 95 | var instance = new TypeA(); 96 | container.RegisterInstance(instance).AsSelf(); 97 | container.Register().Singleton().AsSelf(); 98 | container.Register>((c, t) => container.Resolve().GetIntValue).AsSelf(); 99 | Assert.AreEqual(100, container.Resolve>()()); 100 | } 101 | 102 | [Test] 103 | public void should_override_register() 104 | { 105 | var container = new Container(); 106 | container.RegisterInstance(10).AsSelf(); 107 | container.RegisterInstance(20).AsSelf(); 108 | Assert.AreEqual(20, container.Resolve()); 109 | } 110 | 111 | [Test] 112 | public void should_throw_if_cannot_resolve() 113 | { 114 | var container = new Container(); 115 | container.Register().Singleton().AsSelf(); 116 | Assert.Catch(() => container.Resolve()); 117 | Assert.Catch(() => container.Resolve()); 118 | } 119 | 120 | class Injected 121 | { 122 | [Inject] public int Int; 123 | [Inject] public float Float { get; private set; } 124 | [field: Inject] public Double Double { get; } 125 | 126 | public int A; 127 | public double B; 128 | 129 | [Inject] 130 | public void Init(int a, double b) 131 | { 132 | A = a; 133 | B = b; 134 | } 135 | 136 | public float C; 137 | public long D; 138 | 139 | [Inject] 140 | public int Init(float c, long d = 20) 141 | { 142 | C = c; 143 | D = d; 144 | return (int)d; 145 | } 146 | 147 | public int E; 148 | void Init(int e) 149 | { 150 | E = e; 151 | } 152 | } 153 | 154 | [Test] 155 | public void should_inject_marked_members() 156 | { 157 | var container = new Container(); 158 | container.RegisterInstance(10).AsSelf(); 159 | container.RegisterInstance(100f).AsSelf(); 160 | container.RegisterInstance(0.999).AsSelf(); 161 | var instance = new Injected(); 162 | container.InjectAll(instance); 163 | Assert.AreEqual(10, instance.Int); 164 | Assert.AreEqual(100f, instance.Float); 165 | Assert.AreEqual(0.999, instance.Double); 166 | Assert.AreEqual(10, instance.A); 167 | Assert.AreEqual(0.999, instance.B); 168 | Assert.AreEqual(100f, instance.C); 169 | Assert.AreEqual(20, instance.D); 170 | Assert.AreEqual(0, instance.E); 171 | } 172 | 173 | class CannotInject 174 | { 175 | [Inject] public int A { get; } 176 | } 177 | 178 | [Test] 179 | public void should_throw_on_inject_to_readonly_property() 180 | { 181 | var container = new Container(); 182 | container.RegisterInstance(10).AsSelf(); 183 | Assert.Catch(() => container.InjectAll(new CannotInject())); 184 | } 185 | 186 | [Test] 187 | public void should_throw_if_not_able_to_inject() 188 | { 189 | var container = new Container(); 190 | Assert.Catch(() => container.InjectAll(new Injected())); 191 | } 192 | 193 | [Test] 194 | public void should_inject_and_call_function() 195 | { 196 | var container = new Container(); 197 | container.RegisterInstance(10).AsSelf(); 198 | Assert.AreEqual(20, container.CallFunc>(v => v * 2)); 199 | } 200 | 201 | [Test] 202 | public void should_inject_and_call_func_with_default_argument() 203 | { 204 | var container = new Container(); 205 | container.RegisterInstance(100).AsSelf(); 206 | Assert.AreEqual(200f, container.CallFunc>(AddFunc)); 207 | } 208 | 209 | float AddFunc(int a, float b = 100) => a + b; 210 | 211 | #if UNITY_EDITOR 212 | [Test] 213 | public void unity_mono_is_not_able_to_resolve_default_parameter_of_local_function() 214 | { 215 | var container = new Container(); 216 | container.RegisterInstance(100).AsSelf(); 217 | Assert.Catch(() => container.CallFunc>(LocalAddFunc)); 218 | float LocalAddFunc(int a, float b = 100) => a + b; 219 | } 220 | #endif 221 | 222 | [Test] 223 | public void should_inject_and_call_action() 224 | { 225 | var container = new Container(); 226 | var intValue = 0; 227 | container.RegisterInstance(10).AsSelf(); 228 | container.CallAction>(value => intValue = value * 2); 229 | Assert.AreEqual(20, intValue); 230 | } 231 | 232 | [Test] 233 | public void should_inject_and_call_action_with_default_argument() 234 | { 235 | var container = new Container(); 236 | container.RegisterInstance(10).AsSelf(); 237 | container.CallAction>(AddAction); 238 | Assert.AreEqual(30f, _value); 239 | } 240 | 241 | private float _value; 242 | void AddAction(int a, float b = 20) => _value = a + b; 243 | 244 | [Test] 245 | public void should_instantiate_by_type() 246 | { 247 | var container = new Container(); 248 | container.Register().Singleton().AsSelf(); 249 | Assert.AreEqual(container.Resolve(), container.Instantiate().TypeA); 250 | } 251 | 252 | class IntArrayClass 253 | { 254 | public readonly int IntValue; 255 | public readonly int[] IntArray; 256 | 257 | public IntArrayClass(int intValue, int[] intArray) 258 | { 259 | IntValue = intValue; 260 | IntArray = intArray; 261 | } 262 | } 263 | 264 | [Test] 265 | public void should_resolve_group_of_type() 266 | { 267 | var container = new Container(); 268 | var child1 = container.CreateChildContainer(); 269 | var child11 = child1.CreateChildContainer(); 270 | var child12 = child1.CreateChildContainer(); 271 | var child2 = container.CreateChildContainer(); 272 | 273 | // Assert.Catch(() => container.ResolveGroup()); 274 | Assert.That(container.ResolveGroup(), Is.Empty); 275 | 276 | container.RegisterInstance(10).AsSelf(); 277 | container.RegisterInstance(11).AsSelf(); 278 | child1.RegisterInstance(20).AsSelf(); 279 | child1.RegisterInstance(22).AsSelf(); 280 | child2.RegisterInstance(30).AsSelf(); 281 | child11.RegisterInstance(40).AsSelf(); 282 | child12.RegisterInstance(50).AsSelf(); 283 | Assert.That(new[] { 50, 22, 20, 11, 10 }, Is.EqualTo(child12.ResolveGroup())); 284 | Assert.That(new[] { 40, 22, 20, 11, 10 }, Is.EqualTo(child11.ResolveGroup())); 285 | Assert.That(new[] { 30, 11, 10 }, Is.EqualTo(child2.ResolveGroup())); 286 | Assert.That(new[] { 22, 20, 11, 10 }, Is.EqualTo(child1.ResolveGroup())); 287 | Assert.That(new[] { 11, 10 }, Is.EqualTo(container.ResolveGroup())); 288 | 289 | var instance = child12.Instantiate(); 290 | Assert.AreEqual(50, instance.IntValue); 291 | Assert.That(new[] { 50, 22, 20, 11, 10 }, Is.EqualTo(instance.IntArray)); 292 | 293 | instance = container.Instantiate(); 294 | Assert.AreEqual(11, instance.IntValue); 295 | Assert.That(new[] { 11, 10 }, Is.EqualTo(instance.IntArray)); 296 | } 297 | 298 | class InjectMethod 299 | { 300 | [Inject] void Inject(InterfaceA _) {} 301 | } 302 | 303 | [Test] 304 | public void should_able_to_inject_without_resolve() 305 | { 306 | var container = new Container(); 307 | container.Register().Singleton().AsInterfaces(); 308 | Assert.DoesNotThrow(() => container.InjectAll(new InjectMethod())); 309 | } 310 | 311 | class InjectTypeA 312 | { 313 | [Inject] public void Inject(TypeA _) {} 314 | } 315 | 316 | [Test] 317 | public void should_inject_method_to_same_instance_repeatedly() 318 | { 319 | var container = new Container(); 320 | container.Register().AsSelf(); 321 | var instance = new InjectTypeA(); 322 | container.InjectAll(instance); 323 | container.InjectAll(instance); 324 | container.InjectAll(instance); 325 | } 326 | 327 | class TypeAA : TypeA {} 328 | class TypeAAA : TypeAA {} 329 | 330 | [Test] 331 | public void should_register_and_resolve_by_bases() 332 | { 333 | var container = new Container(); 334 | container.Register().AsBases(); 335 | Assert.That(container.Resolve(), Is.InstanceOf()); 336 | Assert.That(container.Resolve(), Is.InstanceOf()); 337 | } 338 | 339 | class InjectFloat 340 | { 341 | [Inject] public float FloatValue; 342 | } 343 | 344 | class InjectIntFloat : InjectFloat 345 | { 346 | [Inject] public int IntValue; 347 | } 348 | 349 | [Test] 350 | public void should_inject_all_for_instance_by_contract_type() 351 | { 352 | var container = new Container(); 353 | container.RegisterInstance(123).AsSelf(); 354 | container.RegisterInstance(222.222f).AsSelf(); 355 | var instance = new InjectIntFloat(); 356 | container.InjectAll((InjectFloat)instance); 357 | Assert.That(instance.IntValue, Is.EqualTo(123)); 358 | Assert.That(instance.FloatValue, Is.EqualTo(222.222f)); 359 | } 360 | 361 | [Test] 362 | public void should_get_null_if_try_resolved_type_not_registered() 363 | { 364 | var container = new Container(); 365 | Assert.That(container.TryResolve(), Is.Null); 366 | } 367 | 368 | [Test] 369 | public void should_check_registered_of_a_type() 370 | { 371 | var container = new Container(); 372 | container.RegisterInstance(123).AsSelf(); 373 | Assert.That(container.IsRegisteredInHierarchy(), Is.True); 374 | Assert.That(container.IsRegisteredInHierarchy(), Is.False); 375 | Assert.That(container.IsRegistered(), Is.True); 376 | Assert.That(container.IsRegistered(), Is.False); 377 | 378 | var child = container.CreateChildContainer(); 379 | Assert.That(child.IsRegisteredInHierarchy(), Is.True); 380 | Assert.That(child.IsRegisteredInHierarchy(), Is.False); 381 | Assert.That(child.IsRegistered(), Is.False); 382 | Assert.That(child.IsRegistered(), Is.False); 383 | } 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /Assets/Tests/TestOneShot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 650be704ac411ca408719adf9d00199e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Tests/TestWithBuilder.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace OneShot.Test 4 | { 5 | public class TestWithBuilder 6 | { 7 | interface InterfaceA {} 8 | class TypeA : InterfaceA {} 9 | 10 | class Foo 11 | { 12 | public int A; 13 | public float B; 14 | public InterfaceA C; 15 | 16 | public Foo(int a, float b, InterfaceA c) 17 | { 18 | A = a; 19 | B = b; 20 | C = c; 21 | } 22 | } 23 | 24 | [Test] 25 | public void should_create_singleton_instance_with_additional_parameters() 26 | { 27 | var container = new Container(); 28 | var typeA = new TypeA(); 29 | container.Register().With(typeA, 1, 123f).Singleton().AsSelf(); 30 | var instance = container.Resolve(); 31 | Assert.That(instance.A, Is.EqualTo(1)); 32 | Assert.That(instance.B, Is.EqualTo(123)); 33 | Assert.That(instance.C, Is.EqualTo(typeA)); 34 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 35 | } 36 | 37 | [Test] 38 | public void should_create_singleton_instance_with_partial_additional_parameters() 39 | { 40 | var container = new Container(); 41 | var typeA = new TypeA(); 42 | container.RegisterInstance(123f).AsSelf(); 43 | container.Register().With(typeA, 1).Singleton().AsSelf(); 44 | var instance = container.Resolve(); 45 | Assert.That(instance.A, Is.EqualTo(1)); 46 | Assert.That(instance.B, Is.EqualTo(123)); 47 | Assert.That(instance.C, Is.EqualTo(typeA)); 48 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 49 | } 50 | 51 | [Test] 52 | public void should_create_singleton_instance_with_partial_and_override_additional_parameters() 53 | { 54 | var container = new Container(); 55 | var typeA = new TypeA(); 56 | container.RegisterInstance(100).AsSelf(); 57 | container.RegisterInstance(123f).AsSelf(); 58 | container.Register().With(typeA, 1).Singleton().AsSelf(); 59 | var instance = container.Resolve(); 60 | Assert.That(instance.A, Is.EqualTo(1)); 61 | Assert.That(instance.B, Is.EqualTo(123)); 62 | Assert.That(instance.C, Is.EqualTo(typeA)); 63 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 64 | } 65 | 66 | [Test] 67 | public void should_create_transient_instance_with_additional_parameters() 68 | { 69 | var container = new Container(); 70 | var typeA = new TypeA(); 71 | container.Register().With(typeA, 1, 123f).Transient().AsSelf(); 72 | var instance = container.Resolve(); 73 | Assert.That(instance.A, Is.EqualTo(1)); 74 | Assert.That(instance.B, Is.EqualTo(123)); 75 | Assert.That(instance.C, Is.EqualTo(typeA)); 76 | Assert.That(container.Resolve(), Is.Not.EqualTo(container.Resolve())); 77 | } 78 | 79 | [Test] 80 | public void should_create_transient_instance_with_partial_additional_parameters() 81 | { 82 | var container = new Container(); 83 | var typeA = new TypeA(); 84 | container.RegisterInstance(1).AsSelf(); 85 | container.Register().With(typeA, 123f).Transient().AsSelf(); 86 | var instance = container.Resolve(); 87 | Assert.That(instance.A, Is.EqualTo(1)); 88 | Assert.That(instance.B, Is.EqualTo(123)); 89 | Assert.That(instance.C, Is.EqualTo(typeA)); 90 | Assert.That(container.Resolve(), Is.Not.EqualTo(container.Resolve())); 91 | } 92 | 93 | [Test] 94 | public void should_create_transient_instance_with_partial_and_override_additional_parameters() 95 | { 96 | var container = new Container(); 97 | var typeA = new TypeA(); 98 | container.RegisterInstance(456f).AsSelf(); 99 | container.RegisterInstance(1).AsSelf(); 100 | container.Register().With(typeA, 123f).Transient().AsSelf(); 101 | var instance = container.Resolve(); 102 | Assert.That(instance.A, Is.EqualTo(1)); 103 | Assert.That(instance.B, Is.EqualTo(123)); 104 | Assert.That(instance.C, Is.EqualTo(typeA)); 105 | Assert.That(container.Resolve(), Is.Not.EqualTo(container.Resolve())); 106 | } 107 | 108 | [Test] 109 | public void should_create_scoped_instance_with_additional_parameters() 110 | { 111 | var container = new Container(); 112 | var typeA = new TypeA(); 113 | container.Register().With(typeA, 1, 123f).Scoped().AsSelf(); 114 | var instance = container.Resolve(); 115 | Assert.That(instance.A, Is.EqualTo(1)); 116 | Assert.That(instance.B, Is.EqualTo(123)); 117 | Assert.That(instance.C, Is.EqualTo(typeA)); 118 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 119 | 120 | var scopedFoo = container.BeginScope().Resolve(); 121 | Assert.That(scopedFoo.A, Is.EqualTo(1)); 122 | Assert.That(scopedFoo.B, Is.EqualTo(123)); 123 | Assert.That(scopedFoo.C, Is.EqualTo(typeA)); 124 | Assert.That(instance, Is.Not.EqualTo(scopedFoo)); 125 | } 126 | 127 | [Test] 128 | public void should_create_scoped_instance_with_partial_additional_parameters() 129 | { 130 | var container = new Container(); 131 | container.Register().Singleton().AsInterfaces(); 132 | container.Register().With(1, 123f).Scoped().AsSelf(); 133 | var typeA = container.Resolve(); 134 | var instance = container.Resolve(); 135 | Assert.That(instance.A, Is.EqualTo(1)); 136 | Assert.That(instance.B, Is.EqualTo(123)); 137 | Assert.That(instance.C, Is.EqualTo(typeA)); 138 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 139 | 140 | var scopedFoo = container.BeginScope().Resolve(); 141 | Assert.That(scopedFoo.A, Is.EqualTo(1)); 142 | Assert.That(scopedFoo.B, Is.EqualTo(123)); 143 | Assert.That(scopedFoo.C, Is.EqualTo(typeA)); 144 | Assert.That(instance, Is.Not.EqualTo(scopedFoo)); 145 | } 146 | 147 | [Test] 148 | public void should_create_scoped_instance_with_partial_and_override_additional_parameters() 149 | { 150 | var container = new Container(); 151 | container.RegisterInstance(100).AsSelf(); 152 | container.RegisterInstance(666f).AsSelf(); 153 | container.Register().Singleton().AsInterfaces(); 154 | container.Register().With(1, 123f).Scoped().AsSelf(); 155 | 156 | var typeA = container.Resolve(); 157 | var instance = container.Resolve(); 158 | Assert.That(instance.A, Is.EqualTo(1)); 159 | Assert.That(instance.B, Is.EqualTo(123)); 160 | Assert.That(instance.C, Is.EqualTo(typeA)); 161 | Assert.That(container.Resolve(), Is.EqualTo(container.Resolve())); 162 | 163 | var scopedFoo = container.BeginScope().Resolve(); 164 | Assert.That(scopedFoo.A, Is.EqualTo(1)); 165 | Assert.That(scopedFoo.B, Is.EqualTo(123)); 166 | Assert.That(scopedFoo.C, Is.EqualTo(typeA)); 167 | Assert.That(instance, Is.Not.EqualTo(scopedFoo)); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Assets/Tests/TestWithBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d294b112a9124c18b43e90dafaaa7ffa 3 | timeCreated: 1656744741 -------------------------------------------------------------------------------- /Assets/Tests/Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tests", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner", 7 | "OneShot" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "overrideReferences": true, 15 | "precompiledReferences": [ 16 | "nunit.framework.dll" 17 | ], 18 | "autoReferenced": false, 19 | "defineConstraints": [ 20 | "UNITY_INCLUDE_TESTS" 21 | ], 22 | "versionDefines": [], 23 | "noEngineReferences": false 24 | } -------------------------------------------------------------------------------- /Assets/Tests/Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 011f84fa1c9cc4343be327c1887dc114 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 quabug 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 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/ContainerComponent.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System; 4 | using System.Linq; 5 | using UnityEngine; 6 | #if UNITY_EDITOR 7 | using UnityEditor; 8 | #endif 9 | 10 | namespace OneShot 11 | { 12 | public sealed class ContainerComponent : MonoBehaviour 13 | { 14 | public Container Value { get; set; } = default!; 15 | private void OnDestroy() => Value.Dispose(); 16 | } 17 | 18 | #if UNITY_EDITOR 19 | [CustomEditor(typeof(ContainerComponent))] 20 | public sealed class ContainerComponentDrawer : Editor 21 | { 22 | private ContainerComponent _container = default!; 23 | 24 | private void OnEnable() { 25 | _container = (ContainerComponent) target; 26 | } 27 | 28 | public override void OnInspectorGUI() { 29 | base.OnInspectorGUI(); 30 | using var _ = new EditorGUI.DisabledScope(true); 31 | foreach (var (type, resolverStack) in _container.Value.Resolvers) 32 | { 33 | var label = $"{type.Name}({resolverStack.Count})"; 34 | var resolversText = resolverStack.Select(resolver => resolver.Lifetime).Select(lifetime => lifetime switch 35 | { 36 | ResolverLifetime.Singleton => "1", 37 | ResolverLifetime.Transient => "*", 38 | ResolverLifetime.Scoped => "<1>", 39 | _ => throw new NotSupportedException() 40 | }); 41 | EditorGUILayout.TextField(label, string.Join("|", resolversText)); 42 | } 43 | } 44 | } 45 | #endif 46 | } 47 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/ContainerComponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15dec7edbc1843998b843ff4a889f2d5 3 | timeCreated: 1692349558 -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/Injector.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEngine.Pool; 6 | using UnityEngine.SceneManagement; 7 | 8 | namespace OneShot 9 | { 10 | public interface IInjectable 11 | { 12 | } 13 | 14 | public interface IInstaller 15 | { 16 | void Install(Container container); 17 | } 18 | 19 | [DisallowMultipleComponent] 20 | public sealed class Injector : MonoBehaviour 21 | { 22 | public enum Phase { Awake, Start, Update, LateUpdate, Manual } 23 | 24 | [field: SerializeField] public Phase InjectPhase { get; private set; } = Phase.Start; 25 | [field: SerializeField] public bool InjectableOnly { get; private set; } = false; 26 | [field: SerializeField] public int RecursiveDepth { get; private set; } = -1; 27 | [field: SerializeField] public bool StopOnInactiveObject { get; private set; } = false; 28 | 29 | private void Awake() 30 | { 31 | if (InjectPhase == Phase.Awake) Inject(); 32 | } 33 | 34 | private void Start() 35 | { 36 | if (InjectPhase == Phase.Start) Inject(); 37 | } 38 | 39 | private void Update() 40 | { 41 | if (InjectPhase == Phase.Update) Inject(); 42 | } 43 | 44 | private void LateUpdate() 45 | { 46 | if (InjectPhase == Phase.LateUpdate) Inject(); 47 | } 48 | 49 | public void Inject(Container container) 50 | { 51 | Debug.Assert(enabled, "Inject already called"); 52 | enabled = false; 53 | if (InjectableOnly) container.RecursiveInjectAll(gameObject, StopOnInactiveObject, RecursiveDepth); 54 | else container.RecursiveInjectAll(gameObject, StopOnInactiveObject, RecursiveDepth); 55 | } 56 | 57 | private void Inject() 58 | { 59 | var container = new Container(); 60 | container.RegisterInstance(container).AsSelf(); 61 | gameObject.AddComponent().Value = container; 62 | Inject(container); 63 | } 64 | } 65 | 66 | public static class RecursiveInjectorExtension 67 | { 68 | public static void InjectScene(this Container container, Scene scene) 69 | { 70 | var roots = ListPool.Get(); 71 | try 72 | { 73 | scene.GetRootGameObjects(roots); 74 | foreach (var obj in roots) 75 | { 76 | if (obj.TryGetComponent(out var injector) && injector.InjectPhase == Injector.Phase.Manual) 77 | { 78 | injector.Inject(container); 79 | } 80 | } 81 | } 82 | finally 83 | { 84 | ListPool.Release(roots); 85 | } 86 | } 87 | 88 | 89 | public static void InjectGameObject(this Container container, GameObject gameObject) 90 | { 91 | var components = ListPool.Get(); 92 | try 93 | { 94 | gameObject.GetComponents(components); 95 | foreach (var component in components) container.InjectAll(component); 96 | } 97 | finally 98 | { 99 | ListPool.Release(components); 100 | } 101 | } 102 | 103 | public static void TryInstallGameObject(this Container container, GameObject self) 104 | { 105 | var installers = ListPool.Get(); 106 | try 107 | { 108 | self.GetComponents(installers); 109 | foreach (var installer in installers) container.InjectAll(installer); 110 | 111 | if (installers.Any()) 112 | { 113 | container = container.CreateChildContainer(); 114 | container.RegisterInstance(container).AsSelf(); 115 | self.AddComponent().Value = container; 116 | } 117 | 118 | foreach (var installer in installers) installer.Install(container); 119 | } 120 | finally 121 | { 122 | ListPool.Release(installers); 123 | } 124 | } 125 | 126 | private static void InstallAndInjectGameObject(this Container container, GameObject self) 127 | { 128 | container.TryInstallGameObject(self); 129 | // FIXME: avoid inject into `IInstaller` components again? 130 | container.InjectGameObject(self); 131 | } 132 | 133 | public static void RecursiveInjectAll(this Container container, GameObject self, bool stopOnInactiveObject, int depth) 134 | { 135 | if (depth == 0) return; 136 | // skip inactive object and its children 137 | if (stopOnInactiveObject && !self.activeInHierarchy) return; 138 | if (self.TryGetComponent(out _)) return; 139 | 140 | container.InstallAndInjectGameObject(self); 141 | 142 | if (depth > 0) depth--; 143 | if (depth == 0) return; 144 | 145 | for (var i = 0; i < self.transform.childCount; i++) 146 | container.RecursiveInjectAll(self.transform.GetChild(i).gameObject, stopOnInactiveObject, depth); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/Injector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 216e911c2394dac4cab7c7e2c1dbae32 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/OneShot.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OneShot", 3 | "rootNamespace": "OneShot", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } 15 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/OneShot.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0236c215bc7864b95a54f8ee59b23f13 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/OneShot.cs: -------------------------------------------------------------------------------- 1 | // MIT License 2 | 3 | // Copyright (c) 2023 quabug 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 | 23 | using System; 24 | using System.Collections.Concurrent; 25 | using System.Collections.Generic; 26 | using System.Linq; 27 | using System.Reflection; 28 | using System.Runtime.Serialization; 29 | using System.Threading; 30 | using JetBrains.Annotations; 31 | #if !ENABLE_IL2CPP 32 | using System.Linq.Expressions; 33 | #endif 34 | 35 | namespace OneShot 36 | { 37 | public readonly struct Resolver : IEquatable 38 | { 39 | public Func Func { get; } 40 | public ResolverLifetime Lifetime { get; } 41 | public bool IsValid => Func != null; 42 | 43 | public Resolver(Func func, ResolverLifetime lifetime) 44 | { 45 | Func = func; 46 | Lifetime = lifetime; 47 | } 48 | 49 | public bool Equals(Resolver other) => Func.Equals(other.Func) && Lifetime == other.Lifetime; 50 | public override bool Equals(object? obj) => obj is Resolver other && Equals(other); 51 | public override int GetHashCode() => HashCode.Combine(Func, (int)Lifetime); 52 | public static bool operator ==(in Resolver left, in Resolver right) => left.Equals(right); 53 | public static bool operator !=(in Resolver left, in Resolver right) => !(left == right); 54 | } 55 | 56 | public sealed class Container : IDisposable 57 | { 58 | internal Container? Parent { get; private set; } 59 | internal ConcurrentDictionary> Resolvers { get; private set; } = new(); 60 | private ConcurrentStack _disposableInstances = new(); 61 | private ConcurrentStack _children = new(); 62 | 63 | /// 64 | /// enable or disable circular check 65 | /// disable it to improve performance on type resolving. 66 | /// consider disable it on performance critic part and enable it while debugging. 67 | /// 68 | public bool EnableCircularCheck { get; set; } = true; 69 | 70 | /// 71 | /// pre-allocate arguments array of type constructor. 72 | /// enable it to improve performance on resolving but also significant increase memory usage on register. 73 | /// 74 | public bool PreAllocateArgumentArrayOnRegister { get; set; } 75 | 76 | /// 77 | /// https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#disposable-transient-services-captured-by-container 78 | /// 79 | public bool PreventDisposableTransient { get; set; } 80 | 81 | #region creation 82 | 83 | public Container() { } 84 | 85 | public Container(Container parent) 86 | { 87 | Parent = parent; 88 | EnableCircularCheck = parent.EnableCircularCheck; 89 | PreAllocateArgumentArrayOnRegister = parent.PreAllocateArgumentArrayOnRegister; 90 | PreventDisposableTransient = parent.PreventDisposableTransient; 91 | parent._children.Push(this); 92 | } 93 | 94 | public Container CreateChildContainer() 95 | { 96 | return new Container(this); 97 | } 98 | 99 | public Container BeginScope() 100 | { 101 | return CreateChildContainer(); 102 | } 103 | 104 | #endregion 105 | 106 | public void Dispose() 107 | { 108 | if (_children != null!) while (_children.TryPop(out var child)) child.Dispose(); 109 | _children = null!; 110 | if (_disposableInstances != null!) while (_disposableInstances.TryPop(out var instance)) instance.Dispose(); 111 | _disposableInstances = null!; 112 | Parent = null; 113 | Resolvers?.Clear(); 114 | Resolvers = null!; 115 | } 116 | 117 | #region Resolve 118 | 119 | public object Resolve(Type type, Type? label = null) 120 | { 121 | var instance = TryResolve(type, label); 122 | if (instance == null) throw new ArgumentException($"{type.Name} have not been registered yet"); 123 | return instance; 124 | } 125 | 126 | public T Resolve(Type? label = null) 127 | { 128 | return (T)Resolve(typeof(T), label); 129 | } 130 | 131 | public object? TryResolve(Type? label = null) 132 | { 133 | return TryResolve(typeof(T), label); 134 | } 135 | 136 | public object? TryResolve(Type type, Type? label) 137 | { 138 | { 139 | var creatorKey = label == null ? type : label.CreateLabelType(type); 140 | var creator = FindFirstCreatorInHierarchy(creatorKey); 141 | if (creator.IsValid) return creator.Func(this, type); 142 | } 143 | 144 | if (type.IsArray) 145 | { 146 | var elementType = type.GetElementType()!; 147 | var arrayArgument = ResolveGroup(elementType); 148 | var source = arrayArgument.ToArray(); 149 | if (source.Length > 0) 150 | { 151 | var dest = Array.CreateInstance(elementType, source.Length); 152 | Array.Copy(source, dest, source.Length); 153 | return dest; 154 | } 155 | } 156 | 157 | if (type.IsGenericType) 158 | { 159 | var generic = type.GetGenericTypeDefinition(); 160 | var creatorKey = label == null ? generic : label.CreateLabelType(generic); 161 | var creator = FindFirstCreatorInHierarchy(creatorKey); 162 | if (creator.IsValid) return creator.Func(this, type); 163 | } 164 | 165 | return null; 166 | } 167 | 168 | public IEnumerable ResolveGroup() 169 | { 170 | return ResolveGroup(typeof(T)).Cast(); 171 | } 172 | 173 | public IEnumerable ResolveGroup(Type type) 174 | { 175 | var creators = FindCreatorsInHierarchy(this, type).SelectMany(c => c); 176 | return creators.Select(creator => creator.Func(this, type)); 177 | } 178 | 179 | #endregion 180 | 181 | #region Register 182 | 183 | [MustUseReturnValue] 184 | public WithBuilder Register(Type type, Func creator) 185 | { 186 | return new WithBuilder(this, creator, type); 187 | } 188 | 189 | [MustUseReturnValue] 190 | public WithBuilder Register(Type type) 191 | { 192 | var ci = FindConstructorInfo(type); 193 | var (newFunc, parameters, labels) = ci.Compile(); 194 | ThreadLocal? preAllocatedArguments = null; 195 | if (PreAllocateArgumentArrayOnRegister) 196 | { 197 | #pragma warning disable CA2000 // dispose arguments on disposing phase of container 198 | preAllocatedArguments = new ThreadLocal(() => new object[parameters.Length]); 199 | #pragma warning restore CA2000 200 | _disposableInstances.Push(preAllocatedArguments); 201 | } 202 | return Register(type, CreateInstance); 203 | 204 | object CreateInstance(Container resolveContainer, Type _) 205 | { 206 | var enableCircularCheck = EnableCircularCheck; 207 | if (enableCircularCheck) CircularCheck.Begin(type); 208 | try 209 | { 210 | var arguments = preAllocatedArguments?.Value ?? new object[parameters.Length]; 211 | var args = resolveContainer.ResolveParameterInfos(parameters, labels, arguments); 212 | var instance = newFunc(args); 213 | if (instance is IDisposable disposable) resolveContainer._disposableInstances!.Push(disposable); 214 | return instance; 215 | } 216 | finally 217 | { 218 | if (enableCircularCheck) CircularCheck.End(); 219 | } 220 | } 221 | } 222 | 223 | [MustUseReturnValue] 224 | public WithBuilder Register(Func creator) where T : class 225 | { 226 | return Register(typeof(T), creator); 227 | } 228 | 229 | [MustUseReturnValue] 230 | public WithBuilder Register() 231 | { 232 | return Register(typeof(T)); 233 | } 234 | 235 | [MustUseReturnValue] 236 | public ResolverBuilder RegisterInstance(T instance) 237 | { 238 | if (instance == null) throw new ArgumentNullException(nameof(instance)); 239 | return new ResolverBuilder(this, instance.GetType(), (c, t) => instance, ResolverLifetime.Singleton); 240 | } 241 | 242 | public bool IsRegisteredInHierarchy(Type type) 243 | { 244 | return FindFirstCreatorInHierarchy(type).IsValid; 245 | } 246 | 247 | public bool IsRegisteredInHierarchy() 248 | { 249 | return FindFirstCreatorInHierarchy(typeof(T)).IsValid; 250 | } 251 | 252 | public bool IsRegistered(Type type) 253 | { 254 | return FindFirstCreatorInThisContainer(type).IsValid; 255 | } 256 | 257 | public bool IsRegistered() 258 | { 259 | return FindFirstCreatorInThisContainer(typeof(T)).IsValid; 260 | } 261 | 262 | #endregion 263 | 264 | #region Call 265 | 266 | // Unity/Mono: local function with default parameter is not supported by Mono? 267 | public object CallFunc(T func) where T : Delegate 268 | { 269 | var method = func.Method; 270 | if (method.ReturnType == typeof(void)) throw new ArgumentException($"{method.Name} must return void", nameof(func)); 271 | return method.Invoke(func.Target, this); 272 | } 273 | 274 | // Unity/Mono: local function with default parameter is not supported by Mono? 275 | public void CallAction(T action) where T : Delegate 276 | { 277 | action.Method.Invoke(action.Target, this); 278 | } 279 | 280 | #endregion 281 | 282 | #region Instantiate 283 | 284 | public object Instantiate(Type type) 285 | { 286 | return FindConstructorInfo(type).Invoke(this); 287 | } 288 | 289 | public T Instantiate() 290 | { 291 | return (T)Instantiate(typeof(T)); 292 | } 293 | 294 | #endregion 295 | 296 | private static ConstructorInfo FindConstructorInfo(Type type) 297 | { 298 | var constructors = type.GetConstructors(); 299 | ConstructorInfo? ci = null; 300 | if (constructors.Length == 1) ci = constructors[0]; 301 | else if (constructors.Length > 1) ci = constructors.Single(c => c.GetCustomAttribute() != null); 302 | if (ci == null) throw new NotSupportedException($"cannot found constructor of type {type}"); 303 | return ci; 304 | } 305 | 306 | private static IEnumerable> FindCreatorsInHierarchy(Container container, Type type) 307 | { 308 | var current = container; 309 | while (current != null) 310 | { 311 | if (current.Resolvers.TryGetValue(type, out var creators)) 312 | yield return creators; 313 | current = current.Parent; 314 | } 315 | } 316 | 317 | private Resolver FindFirstCreatorInThisContainer(Type type) 318 | { 319 | return Resolvers.TryGetValue(type, out var creators) && creators.TryPeek(out var creator) ? creator : default; 320 | } 321 | 322 | private Resolver FindFirstCreatorInHierarchy(Type type) 323 | { 324 | var current = this; 325 | while (current != null) 326 | { 327 | var creator = current.FindFirstCreatorInThisContainer(type); 328 | if (creator.IsValid) return creator; 329 | current = current.Parent; 330 | } 331 | return default; 332 | } 333 | 334 | private object ResolveParameterInfo(ParameterInfo parameter, Type? label = null) 335 | { 336 | var parameterType = parameter.ParameterType; 337 | var instance = TryResolve(parameterType, label); 338 | if (instance != null) return instance; 339 | return parameter.HasDefaultValue ? parameter.DefaultValue! : throw new ArgumentException($"cannot resolve parameter {parameter.Member.DeclaringType?.Name}.{parameter.Member.Name}.{parameter.Name}"); 340 | } 341 | 342 | internal object[] ResolveParameterInfos(ParameterInfo[] parameters, Type?[] labels, object[] arguments) 343 | { 344 | for (var i = 0; i < parameters.Length; i++) 345 | { 346 | var parameter = parameters[i]; 347 | var label = labels[i]; 348 | arguments[i] = ResolveParameterInfo(parameter, label); 349 | } 350 | return arguments; 351 | } 352 | } 353 | 354 | [UsedImplicitly] 355 | [MeansImplicitUse(ImplicitUseKindFlags.Assign)] 356 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] 357 | public sealed class InjectAttribute : Attribute 358 | { 359 | public Type? Label { get; } 360 | public InjectAttribute(Type? label = null) => Label = label; 361 | } 362 | 363 | // ReSharper disable once UnusedTypeParameter 364 | #pragma warning disable CA1040 365 | public interface ILabel { } 366 | #pragma warning restore CA1040 367 | 368 | public enum ResolverLifetime { Transient, Singleton, Scoped } 369 | 370 | public class ResolverBuilder 371 | { 372 | internal Container Container { get; } 373 | internal Resolver Resolver { get; } 374 | internal Type ConcreteType { get; } 375 | 376 | internal ResolverBuilder(Container container, Type concreteType, Func creator, ResolverLifetime lifetime) 377 | { 378 | Container = container; 379 | Resolver = new Resolver(creator, lifetime); 380 | ConcreteType = concreteType; 381 | } 382 | 383 | public ResolverBuilder As(Type contractType, Type? label = null) 384 | { 385 | if (Container.PreventDisposableTransient && Resolver.Lifetime == ResolverLifetime.Transient && typeof(IDisposable).IsAssignableFrom(ConcreteType)) 386 | throw new ArgumentException($"disposable type {ConcreteType} cannot register as transient. this check can be disabled by set {nameof(OneShot.Container.PreventDisposableTransient)} to false."); 387 | if (!contractType.IsAssignableFrom(ConcreteType)) throw new ArgumentException($"concreteType({ConcreteType}) must derived from contractType({contractType})", nameof(contractType)); 388 | if (label != null) contractType = label.CreateLabelType(contractType); 389 | var resolverStack = GetOrCreateResolverStack(contractType); 390 | if (!resolverStack.Contains(Resolver)) resolverStack.Push(Resolver); 391 | return this; 392 | } 393 | 394 | public ResolverBuilder As(Type? label = null) 395 | { 396 | return As(typeof(T), label); 397 | } 398 | 399 | public ResolverBuilder AsSelf(Type? label = null) 400 | { 401 | return As(ConcreteType, label); 402 | } 403 | 404 | public ResolverBuilder AsInterfaces(Type? label = null) 405 | { 406 | foreach (var @interface in ConcreteType.GetInterfaces()) As(@interface, label); 407 | return this; 408 | } 409 | 410 | public ResolverBuilder AsBases(Type? label = null) 411 | { 412 | var baseType = ConcreteType.BaseType; 413 | while (baseType != null && baseType != typeof(Object) && baseType != typeof(ValueType)) 414 | { 415 | As(baseType, label); 416 | baseType = baseType.BaseType; 417 | } 418 | return this; 419 | } 420 | 421 | private ConcurrentStack GetOrCreateResolverStack(Type type) 422 | { 423 | if (!Container.Resolvers.TryGetValue(type, out var resolvers)) 424 | { 425 | resolvers = new ConcurrentStack(); 426 | Container.Resolvers[type] = resolvers; 427 | } 428 | return resolvers; 429 | } 430 | } 431 | 432 | public class LifetimeBuilder : ResolverBuilder 433 | { 434 | internal LifetimeBuilder(Container container, Func creator, Type concreteType) 435 | : base(container, concreteType, creator, ResolverLifetime.Transient) { } 436 | 437 | [MustUseReturnValue] 438 | public ResolverBuilder Transient() 439 | { 440 | return this; 441 | } 442 | 443 | [MustUseReturnValue] 444 | public ResolverBuilder Singleton() 445 | { 446 | var lazyValue = new Lazy(() => Resolver.Func(Container, ConcreteType)); 447 | return new ResolverBuilder(Container, ConcreteType, (container, contractType) => lazyValue.Value, ResolverLifetime.Singleton); 448 | } 449 | 450 | [MustUseReturnValue, Obsolete("use Scoped instead")] 451 | public ResolverBuilder Scope() 452 | { 453 | return Scoped(); 454 | } 455 | 456 | [MustUseReturnValue] 457 | public ResolverBuilder Scoped() 458 | { 459 | var lazyValue = new Lazy(() => Resolver.Func(Container, ConcreteType)); 460 | return new ResolverBuilder(Container, ConcreteType, ResolveScopedInstance, ResolverLifetime.Scoped); 461 | 462 | object ResolveScopedInstance(Container container, Type contractType) 463 | { 464 | if (container == Container) return lazyValue.Value; 465 | // register on runtime should be thread safe? 466 | container.Register(ConcreteType, Resolver.Func).Scoped().As(contractType); 467 | return container.Resolve(contractType); 468 | } 469 | } 470 | } 471 | 472 | public class WithBuilder : LifetimeBuilder 473 | { 474 | public WithBuilder(Container container, Func creator, Type concreteType) : base(container, creator, concreteType) { } 475 | 476 | [MustUseReturnValue] 477 | public LifetimeBuilder With(params object[] instances) 478 | { 479 | return WithImpl(instances.Select(instance => (instance, (Type?)null))); 480 | } 481 | 482 | [MustUseReturnValue] 483 | public LifetimeBuilder With(params (object instance, Type? label)[] labeledInstances) 484 | { 485 | return WithImpl(labeledInstances); 486 | } 487 | 488 | private LifetimeBuilder WithImpl(IEnumerable<(object instance, Type? label)> labeledInstances) 489 | { 490 | #pragma warning disable CA2000 // manually dispose container when the parent container been disposing 491 | Container container = Container.CreateChildContainer(); 492 | #pragma warning restore CA2000 493 | foreach ((object instance, Type? label) in labeledInstances) container.RegisterInstance(instance).AsSelf(label).AsBases(label).AsInterfaces(label); 494 | return new LifetimeBuilder(Container, (_, contractType) => Resolver.Func(container, contractType), ConcreteType); 495 | } 496 | } 497 | 498 | public static class InjectExtension 499 | { 500 | private static readonly Dictionary s_injectors = new(); 501 | 502 | public static void InjectAll(this Container container, object instance, Type instanceType) 503 | { 504 | s_injectors.GetOrCreate(instanceType, () => new TypeInjector(instanceType)).InjectAll(container, instance); 505 | } 506 | 507 | public static void InjectAll(this Container container, T instance) 508 | { 509 | if (instance == null) throw new ArgumentNullException(nameof(instance)); 510 | InjectAll(container, instance, instance.GetType()); 511 | } 512 | } 513 | 514 | sealed class TypeInjector 515 | { 516 | private readonly Type _type; 517 | private readonly List _fields = new List(); 518 | private readonly List _properties = new List(); 519 | private readonly List _methods = new List(); 520 | 521 | public TypeInjector(Type type) 522 | { 523 | _type = type; 524 | const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 525 | foreach (var member in type.GetMembers(flags).Where(mi => mi.GetCustomAttribute() != null)) 526 | { 527 | switch (member) 528 | { 529 | case FieldInfo field: 530 | _fields.Add(field); 531 | break; 532 | case PropertyInfo property: 533 | if (property.CanWrite) _properties.Add(property); 534 | else throw new NotSupportedException($"cannot inject on read-only property {property.DeclaringType.Name}.{property.Name}"); 535 | break; 536 | case MethodInfo method: // TODO: check method validation 537 | _methods.Add(method); 538 | break; 539 | default: 540 | throw new NotSupportedException(); 541 | } 542 | } 543 | } 544 | 545 | public void InjectFields(Container container, object instance) 546 | { 547 | CheckInstanceType(instance); 548 | foreach (var field in _fields) 549 | { 550 | var (setter, label) = field.Compile(); 551 | setter(instance, container.Resolve(field.FieldType, label)); 552 | } 553 | } 554 | 555 | public void InjectProperties(Container container, object instance) 556 | { 557 | CheckInstanceType(instance); 558 | foreach (var property in _properties) 559 | { 560 | var (setter, label) = property.Compile(); 561 | setter(instance, container.Resolve(property.PropertyType, label)); 562 | } 563 | } 564 | 565 | public void InjectMethods(Container container, object instance) 566 | { 567 | foreach (var method in _methods) method.Invoke(instance, container); 568 | } 569 | 570 | public void InjectAll(Container container, object instance) 571 | { 572 | InjectFields(container, instance); 573 | InjectProperties(container, instance); 574 | InjectMethods(container, instance); 575 | } 576 | 577 | private void CheckInstanceType(object instance) 578 | { 579 | if (instance.GetType() != _type) throw new ArgumentException($"mismatch types between {nameof(instance)}({instance.GetType()}) and type({_type})"); 580 | } 581 | } 582 | 583 | internal static class DictionaryExtension 584 | { 585 | public static TValue GetOrCreate( 586 | this Dictionary dictionary, 587 | TKey key 588 | ) where TValue : new() 589 | { 590 | return dictionary.GetOrCreate(key, () => new TValue()); 591 | } 592 | 593 | public static TValue GetOrCreate( 594 | this Dictionary dictionary, 595 | TKey key, 596 | Func newValue 597 | ) 598 | { 599 | if (!dictionary.TryGetValue(key, out var value)) 600 | { 601 | value = newValue(); 602 | dictionary[key] = value; 603 | } 604 | return value; 605 | } 606 | } 607 | 608 | [Serializable] 609 | public class CircularDependencyException : Exception 610 | { 611 | public CircularDependencyException() { } 612 | public CircularDependencyException(string message) : base(message) { } 613 | public CircularDependencyException(string message, Exception inner) : base(message, inner) { } 614 | protected CircularDependencyException(SerializationInfo info, StreamingContext context) : base(info, context) { } 615 | } 616 | 617 | static class CircularCheck 618 | { 619 | private static readonly ThreadLocal> s_circularCheckSet = new(() => new Stack()); 620 | 621 | public static void Begin(Type type) 622 | { 623 | if (s_circularCheckSet.Value.Contains(type)) throw new CircularDependencyException($"circular dependency on {type.Name}"); 624 | s_circularCheckSet.Value.Push(type); 625 | } 626 | 627 | public static void End() 628 | { 629 | s_circularCheckSet.Value.Pop(); 630 | } 631 | } 632 | 633 | static class LabelExtension 634 | { 635 | public static Type CreateLabelType(this Type label, Type contractType) 636 | { 637 | if (label.BaseType != null) throw new ArgumentException($"label {label.FullName} cannot have base type", nameof(label)); 638 | var interfaces = label.GetInterfaces(); 639 | if (interfaces.Length != 1 && interfaces[0].GetGenericTypeDefinition() != typeof(ILabel<>)) 640 | throw new ArgumentException($"label {label.FullName} must implement and only implement {nameof(ILabel)}<> interface.", nameof(label)); 641 | var labelValueType = interfaces[0].GenericTypeArguments[0]; 642 | if (labelValueType.IsGenericParameter) label = label.MakeGenericType(contractType); 643 | else if (labelValueType != contractType) throw new ArgumentException($"Type mismatch between typed label {label.FullName} and {contractType.FullName}"); 644 | return label; 645 | } 646 | } 647 | 648 | static class ConstructorInfoCache 649 | { 650 | private static readonly ConcurrentDictionary, ParameterInfo[], Type?[])> s_compiled = new(); 651 | 652 | public static (Func newFunc, ParameterInfo[] parameters, Type?[] labels) Compile(this ConstructorInfo ci) 653 | { 654 | if (s_compiled.TryGetValue(ci, out var t)) return t; 655 | var parameters = ci.GetParameters(); 656 | var labels = parameters.Select(param => param.GetCustomAttribute()?.Label).ToArray(); 657 | #if ENABLE_IL2CPP 658 | Func func = ci.Invoke; 659 | #else 660 | var @params = Expression.Parameter(typeof(object[])); 661 | var args = parameters.Select((parameter, index) => Expression.Convert( 662 | Expression.ArrayIndex(@params, Expression.Constant(index)), 663 | parameter.ParameterType) 664 | ).Cast().ToArray(); 665 | var @new = Expression.New(ci, args); 666 | var lambda = Expression.Lambda(typeof(Func), Expression.Convert(@new, typeof(object)), @params); 667 | var func = (Func)lambda.Compile(); 668 | #endif 669 | s_compiled.TryAdd(ci, (func, parameters, labels)); 670 | return (func, parameters, labels); 671 | } 672 | 673 | public static object Invoke(this ConstructorInfo ci, Container container) 674 | { 675 | var (newFunc, parameters, labels) = ci.Compile(); 676 | var arguments = new object[parameters.Length]; 677 | var args = container.ResolveParameterInfos(parameters, labels, arguments); 678 | return newFunc(args); 679 | } 680 | } 681 | 682 | static class MethodInfoCache 683 | { 684 | private static readonly ConcurrentDictionary, ParameterInfo[], Type?[])> s_compiled = new(); 685 | 686 | public static (Func call, ParameterInfo[] parameters, Type?[] labels) Compile(this MethodInfo mi) 687 | { 688 | if (s_compiled.TryGetValue(mi, out var t)) return t; 689 | var parameters = mi.GetParameters(); 690 | var labels = parameters.Select(param => param.GetCustomAttribute()?.Label).ToArray(); 691 | s_compiled.TryAdd(mi, (mi.Invoke, parameters, labels)); 692 | return (mi.Invoke, parameters, labels); 693 | } 694 | 695 | public static object Invoke(this MethodInfo mi, object target, Container container) 696 | { 697 | var (call, parameters, labels) = mi.Compile(); 698 | var arguments = new object[parameters.Length]; 699 | var args = container.ResolveParameterInfos(parameters, labels, arguments); 700 | return call(target, args); 701 | } 702 | } 703 | 704 | static class PropertyInfoCache 705 | { 706 | private static readonly ConcurrentDictionary, Type?)> s_compiled = new(); 707 | 708 | public static (Action setValue, Type? label) Compile(this PropertyInfo pi) 709 | { 710 | if (s_compiled.TryGetValue(pi, out var t)) return t; 711 | var label = pi.GetCustomAttribute()?.Label; 712 | s_compiled.TryAdd(pi, (pi.SetValue, label)); 713 | return (pi.SetValue, label); 714 | } 715 | } 716 | 717 | static class FieldInfoCache 718 | { 719 | private static readonly ConcurrentDictionary, Type?)> s_compiled = new(); 720 | 721 | public static (Action setValue, Type? label) Compile(this FieldInfo fi) 722 | { 723 | if (s_compiled.TryGetValue(fi, out var t)) return t; 724 | var label = fi.GetCustomAttribute()?.Label; 725 | s_compiled.TryAdd(fi, (fi.SetValue, label)); 726 | return (fi.SetValue, label); 727 | } 728 | } 729 | 730 | public static class GenericExtension 731 | { 732 | [MustUseReturnValue] 733 | public static WithBuilder RegisterGeneric(this Container container, Type genericType, MethodInfo creator) 734 | { 735 | if (genericType == null) throw new ArgumentNullException(nameof(genericType)); 736 | if (creator == null) throw new ArgumentNullException(nameof(creator)); 737 | if (!genericType.IsGenericType) throw new ArgumentException($"{genericType.FullName} is not a generic type", nameof(genericType)); 738 | if (!creator.IsStatic) throw new ArgumentException($"{creator.Name} is not static", nameof(creator)); 739 | if (!creator.ReturnType.IsGenericType || creator.ReturnType.GetGenericTypeDefinition() != genericType) throw new ArgumentException($"the return type ({creator.ReturnType}) of {creator.Name} require to be the same as {nameof(genericType)} ({genericType})", nameof(creator)); 740 | // TODO: check constraint of generic argument 741 | if (creator.GetGenericArguments().Length != genericType.GetGenericArguments().Length) throw new ArgumentException($"the method has different generic arguments: actual={creator.GetGenericArguments().Length} expected={genericType.GetGenericArguments()}", nameof(creator)); 742 | var parameters = creator.GetParameters(); 743 | if (parameters.Length != 2 || parameters[0].ParameterType != typeof(Container) || parameters[1].ParameterType != typeof(Type)) throw new ArgumentException("creator must have exact parameter of (Container, Type)", nameof(creator)); 744 | return container.Register(genericType, GetInstanceCreator(creator)); 745 | 746 | static Func GetInstanceCreator(MethodInfo creator) 747 | { 748 | return (container, type) => creator.MakeGenericMethod(type.GetGenericArguments()).Invoke(null, new object[] { container, type }); 749 | } 750 | } 751 | } 752 | } 753 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/OneShot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2d3d03706b3e542fa8d69a9ef94f2ae1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/StopInjection.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace OneShot 4 | { 5 | [DisallowMultipleComponent] 6 | public sealed class StopInjection : MonoBehaviour 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/StopInjection.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b78e48aaf11b414d91cefd33176e47bd 3 | timeCreated: 1692354141 -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.quabug.one-shot-injection", 3 | "version": "3.0.1", 4 | "displayName": "One Shot Dependency Injection", 5 | "description": "A single file DI container", 6 | "type": "library" 7 | } 8 | -------------------------------------------------------------------------------- /Packages/com.quabug.one-shot-injection/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2097fbd87c257454b80dbb65b981a2e3 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ide.rider": "3.0.24", 4 | "com.unity.ide.visualstudio": "2.0.20", 5 | "com.unity.ide.vscode": "1.2.5", 6 | "com.unity.test-framework.performance": "3.0.2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Packages/packages-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.quabug.one-shot-injection": { 4 | "version": "file:com.quabug.one-shot-injection", 5 | "depth": 0, 6 | "source": "embedded", 7 | "dependencies": {} 8 | }, 9 | "com.unity.ext.nunit": { 10 | "version": "1.0.6", 11 | "depth": 1, 12 | "source": "registry", 13 | "dependencies": {}, 14 | "url": "https://packages.unity.com" 15 | }, 16 | "com.unity.ide.rider": { 17 | "version": "3.0.24", 18 | "depth": 0, 19 | "source": "registry", 20 | "dependencies": { 21 | "com.unity.ext.nunit": "1.0.6" 22 | }, 23 | "url": "https://packages.unity.com" 24 | }, 25 | "com.unity.ide.visualstudio": { 26 | "version": "2.0.20", 27 | "depth": 0, 28 | "source": "registry", 29 | "dependencies": { 30 | "com.unity.test-framework": "1.1.9" 31 | }, 32 | "url": "https://packages.unity.com" 33 | }, 34 | "com.unity.ide.vscode": { 35 | "version": "1.2.5", 36 | "depth": 0, 37 | "source": "registry", 38 | "dependencies": {}, 39 | "url": "https://packages.unity.com" 40 | }, 41 | "com.unity.test-framework": { 42 | "version": "1.1.33", 43 | "depth": 1, 44 | "source": "registry", 45 | "dependencies": { 46 | "com.unity.ext.nunit": "1.0.6", 47 | "com.unity.modules.imgui": "1.0.0", 48 | "com.unity.modules.jsonserialize": "1.0.0" 49 | }, 50 | "url": "https://packages.unity.com" 51 | }, 52 | "com.unity.test-framework.performance": { 53 | "version": "3.0.2", 54 | "depth": 0, 55 | "source": "registry", 56 | "dependencies": { 57 | "com.unity.test-framework": "1.1.31", 58 | "com.unity.modules.jsonserialize": "1.0.0" 59 | }, 60 | "url": "https://packages.unity.com" 61 | }, 62 | "com.unity.modules.imgui": { 63 | "version": "1.0.0", 64 | "depth": 2, 65 | "source": "builtin", 66 | "dependencies": {} 67 | }, 68 | "com.unity.modules.jsonserialize": { 69 | "version": "1.0.0", 70 | "depth": 1, 71 | "source": "builtin", 72 | "dependencies": {} 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 0 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 0 30 | m_SerializeInlineMappingsOnOneLine: 1 -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | m_LogWhenShaderIsCompiled: 0 63 | m_AllowEnlightenSupportForUpgradedProject: 0 64 | -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /ProjectSettings/MemorySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!387306366 &1 4 | MemorySettings: 5 | m_ObjectHideFlags: 0 6 | m_EditorMemorySettings: 7 | m_MainAllocatorBlockSize: -1 8 | m_ThreadAllocatorBlockSize: -1 9 | m_MainGfxBlockSize: -1 10 | m_ThreadGfxBlockSize: -1 11 | m_CacheBlockSize: -1 12 | m_TypetreeBlockSize: -1 13 | m_ProfilerBlockSize: -1 14 | m_ProfilerEditorBlockSize: -1 15 | m_BucketAllocatorGranularity: -1 16 | m_BucketAllocatorBucketsCount: -1 17 | m_BucketAllocatorBlockSize: -1 18 | m_BucketAllocatorBlockCount: -1 19 | m_ProfilerBucketAllocatorGranularity: -1 20 | m_ProfilerBucketAllocatorBucketsCount: -1 21 | m_ProfilerBucketAllocatorBlockSize: -1 22 | m_ProfilerBucketAllocatorBlockCount: -1 23 | m_TempAllocatorSizeMain: -1 24 | m_JobTempAllocatorBlockSize: -1 25 | m_BackgroundJobTempAllocatorBlockSize: -1 26 | m_JobTempAllocatorReducedBlockSize: -1 27 | m_TempAllocatorSizeGIBakingWorker: -1 28 | m_TempAllocatorSizeNavMeshWorker: -1 29 | m_TempAllocatorSizeAudioWorker: -1 30 | m_TempAllocatorSizeCloudWorker: -1 31 | m_TempAllocatorSizeGfx: -1 32 | m_TempAllocatorSizeJobWorker: -1 33 | m_TempAllocatorSizeBackgroundWorker: -1 34 | m_TempAllocatorSizePreloadManager: -1 35 | m_PlatformMemorySettings: {} 36 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreviewPackages: 0 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | oneTimeWarningShown: 0 20 | m_Registries: 21 | - m_Id: main 22 | m_Name: 23 | m_Url: https://packages.unity.com 24 | m_Scopes: [] 25 | m_IsDefault: 1 26 | m_Capabilities: 7 27 | m_UserSelectedRegistryName: 28 | m_UserAddingNewScopedRegistry: 0 29 | m_RegistryInfoDraft: 30 | m_ErrorMessage: 31 | m_Original: 32 | m_Id: 33 | m_Name: 34 | m_Url: 35 | m_Scopes: [] 36 | m_IsDefault: 0 37 | m_Capabilities: 0 38 | m_Modified: 0 39 | m_Name: 40 | m_Url: 41 | m_Scopes: 42 | - 43 | m_SelectedScopeIndex: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_DefaultPresets: {} 8 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!129 &1 4 | PlayerSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 24 7 | productGUID: 52d80e5f46e2747cf96f35adfc3dcdc6 8 | AndroidProfiler: 0 9 | AndroidFilterTouchesWhenObscured: 0 10 | AndroidEnableSustainedPerformanceMode: 0 11 | defaultScreenOrientation: 4 12 | targetDevice: 2 13 | useOnDemandResources: 0 14 | accelerometerFrequency: 60 15 | companyName: DefaultCompany 16 | productName: Unity-OneShot 17 | defaultCursor: {fileID: 0} 18 | cursorHotspot: {x: 0, y: 0} 19 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} 20 | m_ShowUnitySplashScreen: 1 21 | m_ShowUnitySplashLogo: 1 22 | m_SplashScreenOverlayOpacity: 1 23 | m_SplashScreenAnimation: 1 24 | m_SplashScreenLogoStyle: 1 25 | m_SplashScreenDrawMode: 0 26 | m_SplashScreenBackgroundAnimationZoom: 1 27 | m_SplashScreenLogoAnimationZoom: 1 28 | m_SplashScreenBackgroundLandscapeAspect: 1 29 | m_SplashScreenBackgroundPortraitAspect: 1 30 | m_SplashScreenBackgroundLandscapeUvs: 31 | serializedVersion: 2 32 | x: 0 33 | y: 0 34 | width: 1 35 | height: 1 36 | m_SplashScreenBackgroundPortraitUvs: 37 | serializedVersion: 2 38 | x: 0 39 | y: 0 40 | width: 1 41 | height: 1 42 | m_SplashScreenLogos: [] 43 | m_VirtualRealitySplashScreen: {fileID: 0} 44 | m_HolographicTrackingLossScreen: {fileID: 0} 45 | defaultScreenWidth: 1024 46 | defaultScreenHeight: 768 47 | defaultScreenWidthWeb: 960 48 | defaultScreenHeightWeb: 600 49 | m_StereoRenderingPath: 0 50 | m_ActiveColorSpace: 0 51 | m_MTRendering: 1 52 | mipStripping: 0 53 | numberOfMipsStripped: 0 54 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000 55 | iosShowActivityIndicatorOnLoading: -1 56 | androidShowActivityIndicatorOnLoading: -1 57 | iosUseCustomAppBackgroundBehavior: 0 58 | iosAllowHTTPDownload: 1 59 | allowedAutorotateToPortrait: 1 60 | allowedAutorotateToPortraitUpsideDown: 1 61 | allowedAutorotateToLandscapeRight: 1 62 | allowedAutorotateToLandscapeLeft: 1 63 | useOSAutorotation: 1 64 | use32BitDisplayBuffer: 1 65 | preserveFramebufferAlpha: 0 66 | disableDepthAndStencilBuffers: 0 67 | androidStartInFullscreen: 1 68 | androidRenderOutsideSafeArea: 1 69 | androidUseSwappy: 1 70 | androidBlitType: 0 71 | androidResizableWindow: 0 72 | androidDefaultWindowWidth: 1920 73 | androidDefaultWindowHeight: 1080 74 | androidMinimumWindowWidth: 400 75 | androidMinimumWindowHeight: 300 76 | androidFullscreenMode: 1 77 | defaultIsNativeResolution: 1 78 | macRetinaSupport: 1 79 | runInBackground: 1 80 | captureSingleScreen: 0 81 | muteOtherAudioSources: 0 82 | Prepare IOS For Recording: 0 83 | Force IOS Speakers When Recording: 0 84 | deferSystemGesturesMode: 0 85 | hideHomeButton: 0 86 | submitAnalytics: 1 87 | usePlayerLog: 1 88 | bakeCollisionMeshes: 0 89 | forceSingleInstance: 0 90 | useFlipModelSwapchain: 1 91 | resizableWindow: 0 92 | useMacAppStoreValidation: 0 93 | macAppStoreCategory: public.app-category.games 94 | gpuSkinning: 1 95 | xboxPIXTextureCapture: 0 96 | xboxEnableAvatar: 0 97 | xboxEnableKinect: 0 98 | xboxEnableKinectAutoTracking: 0 99 | xboxEnableFitness: 0 100 | visibleInBackground: 1 101 | allowFullscreenSwitch: 1 102 | fullscreenMode: 1 103 | xboxSpeechDB: 0 104 | xboxEnableHeadOrientation: 0 105 | xboxEnableGuest: 0 106 | xboxEnablePIXSampling: 0 107 | metalFramebufferOnly: 0 108 | xboxOneResolution: 0 109 | xboxOneSResolution: 0 110 | xboxOneXResolution: 3 111 | xboxOneMonoLoggingLevel: 0 112 | xboxOneLoggingLevel: 1 113 | xboxOneDisableEsram: 0 114 | xboxOneEnableTypeOptimization: 0 115 | xboxOnePresentImmediateThreshold: 0 116 | switchQueueCommandMemory: 0 117 | switchQueueControlMemory: 16384 118 | switchQueueComputeMemory: 262144 119 | switchNVNShaderPoolsGranularity: 33554432 120 | switchNVNDefaultPoolsGranularity: 16777216 121 | switchNVNOtherPoolsGranularity: 16777216 122 | switchNVNMaxPublicTextureIDCount: 0 123 | switchNVNMaxPublicSamplerIDCount: 0 124 | stadiaPresentMode: 0 125 | stadiaTargetFramerate: 0 126 | vulkanNumSwapchainBuffers: 3 127 | vulkanEnableSetSRGBWrite: 0 128 | vulkanEnablePreTransform: 0 129 | vulkanEnableLateAcquireNextImage: 0 130 | vulkanEnableCommandBufferRecycling: 1 131 | m_SupportedAspectRatios: 132 | 4:3: 1 133 | 5:4: 1 134 | 16:10: 1 135 | 16:9: 1 136 | Others: 1 137 | bundleVersion: 0.1 138 | preloadedAssets: [] 139 | metroInputSource: 0 140 | wsaTransparentSwapchain: 0 141 | m_HolographicPauseOnTrackingLoss: 1 142 | xboxOneDisableKinectGpuReservation: 1 143 | xboxOneEnable7thCore: 1 144 | vrSettings: 145 | enable360StereoCapture: 0 146 | isWsaHolographicRemotingEnabled: 0 147 | enableFrameTimingStats: 0 148 | enableOpenGLProfilerGPURecorders: 1 149 | useHDRDisplay: 0 150 | D3DHDRBitDepth: 0 151 | m_ColorGamuts: 00000000 152 | targetPixelDensity: 30 153 | resolutionScalingMode: 0 154 | resetResolutionOnWindowResize: 0 155 | androidSupportedAspectRatio: 1 156 | androidMaxAspectRatio: 2.1 157 | applicationIdentifier: 158 | Standalone: com.DefaultCompany.Unity-OneShot 159 | buildNumber: 160 | Standalone: 0 161 | iPhone: 0 162 | tvOS: 0 163 | overrideDefaultApplicationIdentifier: 0 164 | AndroidBundleVersionCode: 1 165 | AndroidMinSdkVersion: 22 166 | AndroidTargetSdkVersion: 0 167 | AndroidPreferredInstallLocation: 1 168 | aotOptions: 169 | stripEngineCode: 1 170 | iPhoneStrippingLevel: 0 171 | iPhoneScriptCallOptimization: 0 172 | ForceInternetPermission: 0 173 | ForceSDCardPermission: 0 174 | CreateWallpaper: 0 175 | APKExpansionFiles: 0 176 | keepLoadedShadersAlive: 0 177 | StripUnusedMeshComponents: 1 178 | VertexChannelCompressionMask: 4054 179 | iPhoneSdkVersion: 988 180 | iOSTargetOSVersionString: 12.0 181 | tvOSSdkVersion: 0 182 | tvOSRequireExtendedGameController: 0 183 | tvOSTargetOSVersionString: 12.0 184 | uIPrerenderedIcon: 0 185 | uIRequiresPersistentWiFi: 0 186 | uIRequiresFullScreen: 1 187 | uIStatusBarHidden: 1 188 | uIExitOnSuspend: 0 189 | uIStatusBarStyle: 0 190 | appleTVSplashScreen: {fileID: 0} 191 | appleTVSplashScreen2x: {fileID: 0} 192 | tvOSSmallIconLayers: [] 193 | tvOSSmallIconLayers2x: [] 194 | tvOSLargeIconLayers: [] 195 | tvOSLargeIconLayers2x: [] 196 | tvOSTopShelfImageLayers: [] 197 | tvOSTopShelfImageLayers2x: [] 198 | tvOSTopShelfImageWideLayers: [] 199 | tvOSTopShelfImageWideLayers2x: [] 200 | iOSLaunchScreenType: 0 201 | iOSLaunchScreenPortrait: {fileID: 0} 202 | iOSLaunchScreenLandscape: {fileID: 0} 203 | iOSLaunchScreenBackgroundColor: 204 | serializedVersion: 2 205 | rgba: 0 206 | iOSLaunchScreenFillPct: 100 207 | iOSLaunchScreenSize: 100 208 | iOSLaunchScreenCustomXibPath: 209 | iOSLaunchScreeniPadType: 0 210 | iOSLaunchScreeniPadImage: {fileID: 0} 211 | iOSLaunchScreeniPadBackgroundColor: 212 | serializedVersion: 2 213 | rgba: 0 214 | iOSLaunchScreeniPadFillPct: 100 215 | iOSLaunchScreeniPadSize: 100 216 | iOSLaunchScreeniPadCustomXibPath: 217 | iOSLaunchScreenCustomStoryboardPath: 218 | iOSLaunchScreeniPadCustomStoryboardPath: 219 | iOSDeviceRequirements: [] 220 | iOSURLSchemes: [] 221 | macOSURLSchemes: [] 222 | iOSBackgroundModes: 0 223 | iOSMetalForceHardShadows: 0 224 | metalEditorSupport: 1 225 | metalAPIValidation: 1 226 | iOSRenderExtraFrameOnPause: 0 227 | iosCopyPluginsCodeInsteadOfSymlink: 0 228 | appleDeveloperTeamID: 229 | iOSManualSigningProvisioningProfileID: 230 | tvOSManualSigningProvisioningProfileID: 231 | iOSManualSigningProvisioningProfileType: 0 232 | tvOSManualSigningProvisioningProfileType: 0 233 | appleEnableAutomaticSigning: 0 234 | iOSRequireARKit: 0 235 | iOSAutomaticallyDetectAndAddCapabilities: 1 236 | appleEnableProMotion: 0 237 | shaderPrecisionModel: 0 238 | clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea 239 | templatePackageId: com.unity.template.3d@5.0.4 240 | templateDefaultScene: Assets/Scenes/SampleScene.unity 241 | useCustomMainManifest: 0 242 | useCustomLauncherManifest: 0 243 | useCustomMainGradleTemplate: 0 244 | useCustomLauncherGradleManifest: 0 245 | useCustomBaseGradleTemplate: 0 246 | useCustomGradlePropertiesTemplate: 0 247 | useCustomProguardFile: 0 248 | AndroidTargetArchitectures: 1 249 | AndroidTargetDevices: 0 250 | AndroidSplashScreenScale: 0 251 | androidSplashScreen: {fileID: 0} 252 | AndroidKeystoreName: 253 | AndroidKeyaliasName: 254 | AndroidBuildApkPerCpuArchitecture: 0 255 | AndroidTVCompatibility: 0 256 | AndroidIsGame: 1 257 | AndroidEnableTango: 0 258 | androidEnableBanner: 1 259 | androidUseLowAccuracyLocation: 0 260 | androidUseCustomKeystore: 0 261 | m_AndroidBanners: 262 | - width: 320 263 | height: 180 264 | banner: {fileID: 0} 265 | androidGamepadSupportLevel: 0 266 | chromeosInputEmulation: 1 267 | AndroidMinifyWithR8: 0 268 | AndroidMinifyRelease: 0 269 | AndroidMinifyDebug: 0 270 | AndroidValidateAppBundleSize: 1 271 | AndroidAppBundleSizeToValidate: 150 272 | m_BuildTargetIcons: [] 273 | m_BuildTargetPlatformIcons: 274 | - m_BuildTarget: Android 275 | m_Icons: 276 | - m_Textures: [] 277 | m_Width: 432 278 | m_Height: 432 279 | m_Kind: 2 280 | m_SubKind: 281 | - m_Textures: [] 282 | m_Width: 324 283 | m_Height: 324 284 | m_Kind: 2 285 | m_SubKind: 286 | - m_Textures: [] 287 | m_Width: 216 288 | m_Height: 216 289 | m_Kind: 2 290 | m_SubKind: 291 | - m_Textures: [] 292 | m_Width: 162 293 | m_Height: 162 294 | m_Kind: 2 295 | m_SubKind: 296 | - m_Textures: [] 297 | m_Width: 108 298 | m_Height: 108 299 | m_Kind: 2 300 | m_SubKind: 301 | - m_Textures: [] 302 | m_Width: 81 303 | m_Height: 81 304 | m_Kind: 2 305 | m_SubKind: 306 | - m_Textures: [] 307 | m_Width: 192 308 | m_Height: 192 309 | m_Kind: 1 310 | m_SubKind: 311 | - m_Textures: [] 312 | m_Width: 144 313 | m_Height: 144 314 | m_Kind: 1 315 | m_SubKind: 316 | - m_Textures: [] 317 | m_Width: 96 318 | m_Height: 96 319 | m_Kind: 1 320 | m_SubKind: 321 | - m_Textures: [] 322 | m_Width: 72 323 | m_Height: 72 324 | m_Kind: 1 325 | m_SubKind: 326 | - m_Textures: [] 327 | m_Width: 48 328 | m_Height: 48 329 | m_Kind: 1 330 | m_SubKind: 331 | - m_Textures: [] 332 | m_Width: 36 333 | m_Height: 36 334 | m_Kind: 1 335 | m_SubKind: 336 | - m_Textures: [] 337 | m_Width: 192 338 | m_Height: 192 339 | m_Kind: 0 340 | m_SubKind: 341 | - m_Textures: [] 342 | m_Width: 144 343 | m_Height: 144 344 | m_Kind: 0 345 | m_SubKind: 346 | - m_Textures: [] 347 | m_Width: 96 348 | m_Height: 96 349 | m_Kind: 0 350 | m_SubKind: 351 | - m_Textures: [] 352 | m_Width: 72 353 | m_Height: 72 354 | m_Kind: 0 355 | m_SubKind: 356 | - m_Textures: [] 357 | m_Width: 48 358 | m_Height: 48 359 | m_Kind: 0 360 | m_SubKind: 361 | - m_Textures: [] 362 | m_Width: 36 363 | m_Height: 36 364 | m_Kind: 0 365 | m_SubKind: 366 | m_BuildTargetBatching: 367 | - m_BuildTarget: Standalone 368 | m_StaticBatching: 1 369 | m_DynamicBatching: 0 370 | - m_BuildTarget: tvOS 371 | m_StaticBatching: 1 372 | m_DynamicBatching: 0 373 | - m_BuildTarget: Android 374 | m_StaticBatching: 1 375 | m_DynamicBatching: 0 376 | - m_BuildTarget: iPhone 377 | m_StaticBatching: 1 378 | m_DynamicBatching: 0 379 | - m_BuildTarget: WebGL 380 | m_StaticBatching: 0 381 | m_DynamicBatching: 0 382 | m_BuildTargetShaderSettings: [] 383 | m_BuildTargetGraphicsJobs: 384 | - m_BuildTarget: MacStandaloneSupport 385 | m_GraphicsJobs: 0 386 | - m_BuildTarget: Switch 387 | m_GraphicsJobs: 1 388 | - m_BuildTarget: MetroSupport 389 | m_GraphicsJobs: 1 390 | - m_BuildTarget: AppleTVSupport 391 | m_GraphicsJobs: 0 392 | - m_BuildTarget: BJMSupport 393 | m_GraphicsJobs: 1 394 | - m_BuildTarget: LinuxStandaloneSupport 395 | m_GraphicsJobs: 1 396 | - m_BuildTarget: PS4Player 397 | m_GraphicsJobs: 1 398 | - m_BuildTarget: iOSSupport 399 | m_GraphicsJobs: 0 400 | - m_BuildTarget: WindowsStandaloneSupport 401 | m_GraphicsJobs: 1 402 | - m_BuildTarget: XboxOnePlayer 403 | m_GraphicsJobs: 1 404 | - m_BuildTarget: LuminSupport 405 | m_GraphicsJobs: 0 406 | - m_BuildTarget: AndroidPlayer 407 | m_GraphicsJobs: 0 408 | - m_BuildTarget: WebGLSupport 409 | m_GraphicsJobs: 0 410 | m_BuildTargetGraphicsJobMode: 411 | - m_BuildTarget: PS4Player 412 | m_GraphicsJobMode: 0 413 | - m_BuildTarget: XboxOnePlayer 414 | m_GraphicsJobMode: 0 415 | m_BuildTargetGraphicsAPIs: 416 | - m_BuildTarget: AndroidPlayer 417 | m_APIs: 150000000b000000 418 | m_Automatic: 1 419 | - m_BuildTarget: iOSSupport 420 | m_APIs: 10000000 421 | m_Automatic: 1 422 | - m_BuildTarget: AppleTVSupport 423 | m_APIs: 10000000 424 | m_Automatic: 1 425 | - m_BuildTarget: WebGLSupport 426 | m_APIs: 0b000000 427 | m_Automatic: 1 428 | m_BuildTargetVRSettings: 429 | - m_BuildTarget: Standalone 430 | m_Enabled: 0 431 | m_Devices: 432 | - Oculus 433 | - OpenVR 434 | m_DefaultShaderChunkSizeInMB: 16 435 | m_DefaultShaderChunkCount: 0 436 | openGLRequireES31: 0 437 | openGLRequireES31AEP: 0 438 | openGLRequireES32: 0 439 | m_TemplateCustomTags: {} 440 | mobileMTRendering: 441 | Android: 1 442 | iPhone: 1 443 | tvOS: 1 444 | m_BuildTargetGroupLightmapEncodingQuality: [] 445 | m_BuildTargetGroupLightmapSettings: [] 446 | m_BuildTargetNormalMapEncoding: [] 447 | m_BuildTargetDefaultTextureCompressionFormat: [] 448 | playModeTestRunnerEnabled: 0 449 | runPlayModeTestAsEditModeTest: 0 450 | actionOnDotNetUnhandledException: 1 451 | enableInternalProfiler: 0 452 | logObjCUncaughtExceptions: 1 453 | enableCrashReportAPI: 0 454 | cameraUsageDescription: 455 | locationUsageDescription: 456 | microphoneUsageDescription: 457 | bluetoothUsageDescription: 458 | switchNMETAOverride: 459 | switchNetLibKey: 460 | switchSocketMemoryPoolSize: 6144 461 | switchSocketAllocatorPoolSize: 128 462 | switchSocketConcurrencyLimit: 14 463 | switchScreenResolutionBehavior: 2 464 | switchUseCPUProfiler: 0 465 | switchUseGOLDLinker: 0 466 | switchLTOSetting: 0 467 | switchApplicationID: 0x01004b9000490000 468 | switchNSODependencies: 469 | switchTitleNames_0: 470 | switchTitleNames_1: 471 | switchTitleNames_2: 472 | switchTitleNames_3: 473 | switchTitleNames_4: 474 | switchTitleNames_5: 475 | switchTitleNames_6: 476 | switchTitleNames_7: 477 | switchTitleNames_8: 478 | switchTitleNames_9: 479 | switchTitleNames_10: 480 | switchTitleNames_11: 481 | switchTitleNames_12: 482 | switchTitleNames_13: 483 | switchTitleNames_14: 484 | switchTitleNames_15: 485 | switchPublisherNames_0: 486 | switchPublisherNames_1: 487 | switchPublisherNames_2: 488 | switchPublisherNames_3: 489 | switchPublisherNames_4: 490 | switchPublisherNames_5: 491 | switchPublisherNames_6: 492 | switchPublisherNames_7: 493 | switchPublisherNames_8: 494 | switchPublisherNames_9: 495 | switchPublisherNames_10: 496 | switchPublisherNames_11: 497 | switchPublisherNames_12: 498 | switchPublisherNames_13: 499 | switchPublisherNames_14: 500 | switchPublisherNames_15: 501 | switchIcons_0: {fileID: 0} 502 | switchIcons_1: {fileID: 0} 503 | switchIcons_2: {fileID: 0} 504 | switchIcons_3: {fileID: 0} 505 | switchIcons_4: {fileID: 0} 506 | switchIcons_5: {fileID: 0} 507 | switchIcons_6: {fileID: 0} 508 | switchIcons_7: {fileID: 0} 509 | switchIcons_8: {fileID: 0} 510 | switchIcons_9: {fileID: 0} 511 | switchIcons_10: {fileID: 0} 512 | switchIcons_11: {fileID: 0} 513 | switchIcons_12: {fileID: 0} 514 | switchIcons_13: {fileID: 0} 515 | switchIcons_14: {fileID: 0} 516 | switchIcons_15: {fileID: 0} 517 | switchSmallIcons_0: {fileID: 0} 518 | switchSmallIcons_1: {fileID: 0} 519 | switchSmallIcons_2: {fileID: 0} 520 | switchSmallIcons_3: {fileID: 0} 521 | switchSmallIcons_4: {fileID: 0} 522 | switchSmallIcons_5: {fileID: 0} 523 | switchSmallIcons_6: {fileID: 0} 524 | switchSmallIcons_7: {fileID: 0} 525 | switchSmallIcons_8: {fileID: 0} 526 | switchSmallIcons_9: {fileID: 0} 527 | switchSmallIcons_10: {fileID: 0} 528 | switchSmallIcons_11: {fileID: 0} 529 | switchSmallIcons_12: {fileID: 0} 530 | switchSmallIcons_13: {fileID: 0} 531 | switchSmallIcons_14: {fileID: 0} 532 | switchSmallIcons_15: {fileID: 0} 533 | switchManualHTML: 534 | switchAccessibleURLs: 535 | switchLegalInformation: 536 | switchMainThreadStackSize: 1048576 537 | switchPresenceGroupId: 538 | switchLogoHandling: 0 539 | switchReleaseVersion: 0 540 | switchDisplayVersion: 1.0.0 541 | switchStartupUserAccount: 0 542 | switchSupportedLanguagesMask: 0 543 | switchLogoType: 0 544 | switchApplicationErrorCodeCategory: 545 | switchUserAccountSaveDataSize: 0 546 | switchUserAccountSaveDataJournalSize: 0 547 | switchApplicationAttribute: 0 548 | switchCardSpecSize: -1 549 | switchCardSpecClock: -1 550 | switchRatingsMask: 0 551 | switchRatingsInt_0: 0 552 | switchRatingsInt_1: 0 553 | switchRatingsInt_2: 0 554 | switchRatingsInt_3: 0 555 | switchRatingsInt_4: 0 556 | switchRatingsInt_5: 0 557 | switchRatingsInt_6: 0 558 | switchRatingsInt_7: 0 559 | switchRatingsInt_8: 0 560 | switchRatingsInt_9: 0 561 | switchRatingsInt_10: 0 562 | switchRatingsInt_11: 0 563 | switchRatingsInt_12: 0 564 | switchLocalCommunicationIds_0: 565 | switchLocalCommunicationIds_1: 566 | switchLocalCommunicationIds_2: 567 | switchLocalCommunicationIds_3: 568 | switchLocalCommunicationIds_4: 569 | switchLocalCommunicationIds_5: 570 | switchLocalCommunicationIds_6: 571 | switchLocalCommunicationIds_7: 572 | switchParentalControl: 0 573 | switchAllowsScreenshot: 1 574 | switchAllowsVideoCapturing: 1 575 | switchAllowsRuntimeAddOnContentInstall: 0 576 | switchDataLossConfirmation: 0 577 | switchUserAccountLockEnabled: 0 578 | switchSystemResourceMemory: 16777216 579 | switchSupportedNpadStyles: 22 580 | switchNativeFsCacheSize: 32 581 | switchIsHoldTypeHorizontal: 0 582 | switchSupportedNpadCount: 8 583 | switchEnableTouchScreen: 1 584 | switchSocketConfigEnabled: 0 585 | switchTcpInitialSendBufferSize: 32 586 | switchTcpInitialReceiveBufferSize: 64 587 | switchTcpAutoSendBufferSizeMax: 256 588 | switchTcpAutoReceiveBufferSizeMax: 256 589 | switchUdpSendBufferSize: 9 590 | switchUdpReceiveBufferSize: 42 591 | switchSocketBufferEfficiency: 4 592 | switchSocketInitializeEnabled: 1 593 | switchNetworkInterfaceManagerInitializeEnabled: 1 594 | switchPlayerConnectionEnabled: 1 595 | switchUseNewStyleFilepaths: 0 596 | switchUseLegacyFmodPriorities: 1 597 | switchUseMicroSleepForYield: 1 598 | switchEnableRamDiskSupport: 0 599 | switchMicroSleepForYieldTime: 25 600 | switchRamDiskSpaceSize: 12 601 | ps4NPAgeRating: 12 602 | ps4NPTitleSecret: 603 | ps4NPTrophyPackPath: 604 | ps4ParentalLevel: 11 605 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000 606 | ps4Category: 0 607 | ps4MasterVersion: 01.00 608 | ps4AppVersion: 01.00 609 | ps4AppType: 0 610 | ps4ParamSfxPath: 611 | ps4VideoOutPixelFormat: 0 612 | ps4VideoOutInitialWidth: 1920 613 | ps4VideoOutBaseModeInitialWidth: 1920 614 | ps4VideoOutReprojectionRate: 60 615 | ps4PronunciationXMLPath: 616 | ps4PronunciationSIGPath: 617 | ps4BackgroundImagePath: 618 | ps4StartupImagePath: 619 | ps4StartupImagesFolder: 620 | ps4IconImagesFolder: 621 | ps4SaveDataImagePath: 622 | ps4SdkOverride: 623 | ps4BGMPath: 624 | ps4ShareFilePath: 625 | ps4ShareOverlayImagePath: 626 | ps4PrivacyGuardImagePath: 627 | ps4ExtraSceSysFile: 628 | ps4NPtitleDatPath: 629 | ps4RemotePlayKeyAssignment: -1 630 | ps4RemotePlayKeyMappingDir: 631 | ps4PlayTogetherPlayerCount: 0 632 | ps4EnterButtonAssignment: 1 633 | ps4ApplicationParam1: 0 634 | ps4ApplicationParam2: 0 635 | ps4ApplicationParam3: 0 636 | ps4ApplicationParam4: 0 637 | ps4DownloadDataSize: 0 638 | ps4GarlicHeapSize: 2048 639 | ps4ProGarlicHeapSize: 2560 640 | playerPrefsMaxSize: 32768 641 | ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ 642 | ps4pnSessions: 1 643 | ps4pnPresence: 1 644 | ps4pnFriends: 1 645 | ps4pnGameCustomData: 1 646 | playerPrefsSupport: 0 647 | enableApplicationExit: 0 648 | resetTempFolder: 1 649 | restrictedAudioUsageRights: 0 650 | ps4UseResolutionFallback: 0 651 | ps4ReprojectionSupport: 0 652 | ps4UseAudio3dBackend: 0 653 | ps4UseLowGarlicFragmentationMode: 1 654 | ps4SocialScreenEnabled: 0 655 | ps4ScriptOptimizationLevel: 0 656 | ps4Audio3dVirtualSpeakerCount: 14 657 | ps4attribCpuUsage: 0 658 | ps4PatchPkgPath: 659 | ps4PatchLatestPkgPath: 660 | ps4PatchChangeinfoPath: 661 | ps4PatchDayOne: 0 662 | ps4attribUserManagement: 0 663 | ps4attribMoveSupport: 0 664 | ps4attrib3DSupport: 0 665 | ps4attribShareSupport: 0 666 | ps4attribExclusiveVR: 0 667 | ps4disableAutoHideSplash: 0 668 | ps4videoRecordingFeaturesUsed: 0 669 | ps4contentSearchFeaturesUsed: 0 670 | ps4CompatibilityPS5: 0 671 | ps4AllowPS5Detection: 0 672 | ps4GPU800MHz: 1 673 | ps4attribEyeToEyeDistanceSettingVR: 0 674 | ps4IncludedModules: [] 675 | ps4attribVROutputEnabled: 0 676 | monoEnv: 677 | splashScreenBackgroundSourceLandscape: {fileID: 0} 678 | splashScreenBackgroundSourcePortrait: {fileID: 0} 679 | blurSplashScreenBackground: 1 680 | spritePackerPolicy: 681 | webGLMemorySize: 16 682 | webGLExceptionSupport: 1 683 | webGLNameFilesAsHashes: 0 684 | webGLDataCaching: 1 685 | webGLDebugSymbols: 0 686 | webGLEmscriptenArgs: 687 | webGLModulesDirectory: 688 | webGLTemplate: APPLICATION:Default 689 | webGLAnalyzeBuildSize: 0 690 | webGLUseEmbeddedResources: 0 691 | webGLCompressionFormat: 1 692 | webGLWasmArithmeticExceptions: 0 693 | webGLLinkerTarget: 1 694 | webGLThreadsSupport: 0 695 | webGLDecompressionFallback: 0 696 | webGLPowerPreference: 2 697 | scriptingDefineSymbols: {} 698 | additionalCompilerArguments: {} 699 | platformArchitecture: {} 700 | scriptingBackend: {} 701 | il2cppCompilerConfiguration: {} 702 | managedStrippingLevel: 703 | EmbeddedLinux: 1 704 | GameCoreScarlett: 1 705 | GameCoreXboxOne: 1 706 | Lumin: 1 707 | Nintendo Switch: 1 708 | PS4: 1 709 | PS5: 1 710 | Stadia: 1 711 | WebGL: 1 712 | Windows Store Apps: 1 713 | XboxOne: 1 714 | iPhone: 1 715 | tvOS: 1 716 | incrementalIl2cppBuild: {} 717 | suppressCommonWarnings: 1 718 | allowUnsafeCode: 0 719 | useDeterministicCompilation: 1 720 | enableRoslynAnalyzers: 1 721 | selectedPlatform: 0 722 | additionalIl2CppArgs: 723 | scriptingRuntimeVersion: 1 724 | gcIncremental: 1 725 | assemblyVersionValidation: 1 726 | gcWBarrierValidation: 0 727 | apiCompatibilityLevelPerPlatform: {} 728 | m_RenderingPath: 1 729 | m_MobileRenderingPath: 1 730 | metroPackageName: Template_3D 731 | metroPackageVersion: 732 | metroCertificatePath: 733 | metroCertificatePassword: 734 | metroCertificateSubject: 735 | metroCertificateIssuer: 736 | metroCertificateNotAfter: 0000000000000000 737 | metroApplicationDescription: Template_3D 738 | wsaImages: {} 739 | metroTileShortName: 740 | metroTileShowName: 0 741 | metroMediumTileShowName: 0 742 | metroLargeTileShowName: 0 743 | metroWideTileShowName: 0 744 | metroSupportStreamingInstall: 0 745 | metroLastRequiredScene: 0 746 | metroDefaultTileSize: 1 747 | metroTileForegroundText: 2 748 | metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} 749 | metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} 750 | metroSplashScreenUseBackgroundColor: 0 751 | platformCapabilities: {} 752 | metroTargetDeviceFamilies: {} 753 | metroFTAName: 754 | metroFTAFileTypes: [] 755 | metroProtocolName: 756 | vcxProjDefaultLanguage: 757 | XboxOneProductId: 758 | XboxOneUpdateKey: 759 | XboxOneSandboxId: 760 | XboxOneContentId: 761 | XboxOneTitleId: 762 | XboxOneSCId: 763 | XboxOneGameOsOverridePath: 764 | XboxOnePackagingOverridePath: 765 | XboxOneAppManifestOverridePath: 766 | XboxOneVersion: 1.0.0.0 767 | XboxOnePackageEncryption: 0 768 | XboxOnePackageUpdateGranularity: 2 769 | XboxOneDescription: 770 | XboxOneLanguage: 771 | - enus 772 | XboxOneCapability: [] 773 | XboxOneGameRating: {} 774 | XboxOneIsContentPackage: 0 775 | XboxOneEnhancedXboxCompatibilityMode: 0 776 | XboxOneEnableGPUVariability: 1 777 | XboxOneSockets: {} 778 | XboxOneSplashScreen: {fileID: 0} 779 | XboxOneAllowedProductIds: [] 780 | XboxOnePersistentLocalStorageSize: 0 781 | XboxOneXTitleMemory: 8 782 | XboxOneOverrideIdentityName: 783 | XboxOneOverrideIdentityPublisher: 784 | vrEditorSettings: {} 785 | cloudServicesEnabled: 786 | UNet: 1 787 | luminIcon: 788 | m_Name: 789 | m_ModelFolderPath: 790 | m_PortalFolderPath: 791 | luminCert: 792 | m_CertPath: 793 | m_SignPackage: 1 794 | luminIsChannelApp: 0 795 | luminVersion: 796 | m_VersionCode: 1 797 | m_VersionName: 798 | apiCompatibilityLevel: 6 799 | activeInputHandler: 0 800 | windowsGamepadBackendHint: 0 801 | cloudProjectId: 802 | framebufferDepthMemorylessMode: 0 803 | qualitySettingsNames: [] 804 | projectName: 805 | organizationId: 806 | cloudEnabled: 0 807 | legacyClampBlendShapeWeights: 0 808 | playerDataPath: 809 | forceSRGBBlit: 1 810 | virtualTexturingSupportEnabled: 0 811 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2021.3.26f1 2 | m_EditorVersionWithRevision: 2021.3.26f1 (a16dc32e0ff2) 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 0 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | skinWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | customRenderPipeline: {fileID: 0} 44 | excludedTargetPlatforms: [] 45 | m_PerPlatformDefaultQuality: 46 | Android: 0 47 | Lumin: 0 48 | Nintendo 3DS: 0 49 | Nintendo Switch: 0 50 | PS4: 0 51 | PSP2: 0 52 | Stadia: 0 53 | Standalone: 0 54 | WebGL: 0 55 | Windows Store Apps: 0 56 | XboxOne: 0 57 | iPhone: 0 58 | tvOS: 0 59 | -------------------------------------------------------------------------------- /ProjectSettings/SceneTemplateSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "templatePinStates": [], 3 | "dependencyTypeInfos": [ 4 | { 5 | "userAdded": false, 6 | "type": "UnityEngine.AnimationClip", 7 | "ignore": false, 8 | "defaultInstantiationMode": 0, 9 | "supportsModification": true 10 | }, 11 | { 12 | "userAdded": false, 13 | "type": "UnityEditor.Animations.AnimatorController", 14 | "ignore": false, 15 | "defaultInstantiationMode": 0, 16 | "supportsModification": true 17 | }, 18 | { 19 | "userAdded": false, 20 | "type": "UnityEngine.AnimatorOverrideController", 21 | "ignore": false, 22 | "defaultInstantiationMode": 0, 23 | "supportsModification": true 24 | }, 25 | { 26 | "userAdded": false, 27 | "type": "UnityEditor.Audio.AudioMixerController", 28 | "ignore": false, 29 | "defaultInstantiationMode": 0, 30 | "supportsModification": true 31 | }, 32 | { 33 | "userAdded": false, 34 | "type": "UnityEngine.ComputeShader", 35 | "ignore": true, 36 | "defaultInstantiationMode": 1, 37 | "supportsModification": true 38 | }, 39 | { 40 | "userAdded": false, 41 | "type": "UnityEngine.Cubemap", 42 | "ignore": false, 43 | "defaultInstantiationMode": 0, 44 | "supportsModification": true 45 | }, 46 | { 47 | "userAdded": false, 48 | "type": "UnityEngine.GameObject", 49 | "ignore": false, 50 | "defaultInstantiationMode": 0, 51 | "supportsModification": true 52 | }, 53 | { 54 | "userAdded": false, 55 | "type": "UnityEditor.LightingDataAsset", 56 | "ignore": false, 57 | "defaultInstantiationMode": 0, 58 | "supportsModification": false 59 | }, 60 | { 61 | "userAdded": false, 62 | "type": "UnityEngine.LightingSettings", 63 | "ignore": false, 64 | "defaultInstantiationMode": 0, 65 | "supportsModification": true 66 | }, 67 | { 68 | "userAdded": false, 69 | "type": "UnityEngine.Material", 70 | "ignore": false, 71 | "defaultInstantiationMode": 0, 72 | "supportsModification": true 73 | }, 74 | { 75 | "userAdded": false, 76 | "type": "UnityEditor.MonoScript", 77 | "ignore": true, 78 | "defaultInstantiationMode": 1, 79 | "supportsModification": true 80 | }, 81 | { 82 | "userAdded": false, 83 | "type": "UnityEngine.PhysicMaterial", 84 | "ignore": false, 85 | "defaultInstantiationMode": 0, 86 | "supportsModification": true 87 | }, 88 | { 89 | "userAdded": false, 90 | "type": "UnityEngine.PhysicsMaterial2D", 91 | "ignore": false, 92 | "defaultInstantiationMode": 0, 93 | "supportsModification": true 94 | }, 95 | { 96 | "userAdded": false, 97 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", 98 | "ignore": false, 99 | "defaultInstantiationMode": 0, 100 | "supportsModification": true 101 | }, 102 | { 103 | "userAdded": false, 104 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", 105 | "ignore": false, 106 | "defaultInstantiationMode": 0, 107 | "supportsModification": true 108 | }, 109 | { 110 | "userAdded": false, 111 | "type": "UnityEngine.Rendering.VolumeProfile", 112 | "ignore": false, 113 | "defaultInstantiationMode": 0, 114 | "supportsModification": true 115 | }, 116 | { 117 | "userAdded": false, 118 | "type": "UnityEditor.SceneAsset", 119 | "ignore": false, 120 | "defaultInstantiationMode": 0, 121 | "supportsModification": false 122 | }, 123 | { 124 | "userAdded": false, 125 | "type": "UnityEngine.Shader", 126 | "ignore": true, 127 | "defaultInstantiationMode": 1, 128 | "supportsModification": true 129 | }, 130 | { 131 | "userAdded": false, 132 | "type": "UnityEngine.ShaderVariantCollection", 133 | "ignore": true, 134 | "defaultInstantiationMode": 1, 135 | "supportsModification": true 136 | }, 137 | { 138 | "userAdded": false, 139 | "type": "UnityEngine.Texture", 140 | "ignore": false, 141 | "defaultInstantiationMode": 0, 142 | "supportsModification": true 143 | }, 144 | { 145 | "userAdded": false, 146 | "type": "UnityEngine.Texture2D", 147 | "ignore": false, 148 | "defaultInstantiationMode": 0, 149 | "supportsModification": true 150 | }, 151 | { 152 | "userAdded": false, 153 | "type": "UnityEngine.Timeline.TimelineAsset", 154 | "ignore": false, 155 | "defaultInstantiationMode": 0, 156 | "supportsModification": true 157 | } 158 | ], 159 | "defaultDependencyTypeInfo": { 160 | "userAdded": false, 161 | "type": "", 162 | "ignore": false, 163 | "defaultInstantiationMode": 1, 164 | "supportsModification": true 165 | }, 166 | "newSceneOverride": 0 167 | } -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_DashboardUrl: https://dashboard.unity3d.com 13 | m_TestInitMode: 0 14 | CrashReportingSettings: 15 | m_EventUrl: https://perf-events.cloud.unity3d.com 16 | m_Enabled: 0 17 | m_LogBufferSize: 10 18 | m_CaptureEditorExceptions: 1 19 | UnityPurchasingSettings: 20 | m_Enabled: 0 21 | m_TestMode: 0 22 | UnityAnalyticsSettings: 23 | m_Enabled: 0 24 | m_TestMode: 0 25 | m_InitializeOnStartup: 1 26 | UnityAdsSettings: 27 | m_Enabled: 0 28 | m_InitializeOnStartup: 1 29 | m_TestMode: 0 30 | m_IosGameId: 31 | m_AndroidGameId: 32 | m_GameIds: {} 33 | m_GameId: 34 | PerformanceReportingSettings: 35 | m_Enabled: 0 36 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_StripUpdateShader: {fileID: 0} 10 | m_RenderPipeSettingsPath: 11 | m_FixedTimeStep: 0.016666668 12 | m_MaxDeltaTime: 0.05 13 | -------------------------------------------------------------------------------- /ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!890905787 &1 4 | VersionControlSettings: 5 | m_ObjectHideFlags: 0 6 | m_Mode: Visible Meta Files 7 | m_CollabEditorSettings: 8 | inProgressEnabled: 1 9 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /ProjectSettings/boot.config: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quabug/OneShot/209c9292ad32a4b948667ed29c3752e22d8afc87/ProjectSettings/boot.config -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NuGet Badge](https://buildstats.info/nuget/OneShot)](https://www.nuget.org/packages/OneShot/) 2 | [![openupm](https://img.shields.io/npm/v/com.quabug.one-shot-injection?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.quabug.one-shot-injection/) 3 | 4 | # One Shot Dependency Injection 5 | A [single file](Packages/com.quabug.one-shot-injection/OneShot.cs) DI container 6 | 7 | ## Basic Concept of DI 8 | - [How YOU can Learn Dependency Injection in .NET Core and C#](https://softchris.github.io/pages/dotnet-di.html) 9 | - [vContainer](https://vcontainer.hadashikick.jp/about/what-is-di) 10 | 11 | ## Installation 12 | - Copy and paste [OneShot.cs](Packages/com.quabug.one-shot-injection/OneShot.cs) into your project. 13 | - [Unity only] or follow instructions on [OpenUPM](https://openupm.com/packages/com.quabug.one-shot-injection) to install it as a package of Unity. 14 | - [.NET only] or follow instruction on [NuGet](https://www.nuget.org/packages/OneShot/) to install it for .NET project. 15 | 16 | ## Usage 17 | [Test Cases](Assets/Tests) 18 | 19 | ### [Container](Packages/com.quabug.one-shot-injection/OneShot.cs#L39) 20 | A scope mark for registered types. 21 | 22 | ``` c# 23 | // create new container 24 | var container = new Container(); 25 | 26 | // create child container/scope 27 | var child = container.CreateChildContainer(); 28 | 29 | // create a scope container (exactly same as child container) 30 | using (var scope = container.BeginScope()) 31 | 32 | // container options 33 | // enable/disable circular check, enabled by default 34 | container.EnableCircularCheck = false; 35 | 36 | // pre-allocate argument array of registered type, disabled by default 37 | container.PreAllocateArgumentArrayOnRegister = true; 38 | 39 | // throw on register disposable transient, disabled by default 40 | container.PreventDisposableTransient = true; 41 | ``` 42 | 43 | ### [Register Types](Packages/com.quabug.one-shot-injection/OneShot.cs#L147) 44 | ``` c# 45 | container.RegisterInstance(10).AsSelf(); // register instance of int 46 | container.Register().Singleton().AsSelf(); // register a singleton of `Foo` 47 | container.Register().AsSelf(); // register transient of `Bar` 48 | container.Register>((resolveContainer, contractType) => container.Resolve().GetIntValue).AsSelf(); // register `Func` 49 | conatiner.Register().As(); // register interface of `IFoo` 50 | container.Register().With(123, new Bar()).AsSelf(); // register with certain instances 51 | container.Register(typeof(Generic<>), (_, type) => Activator.CreateInstance(type)).As(typeof(Generic<>)); // register generic type 52 | ``` 53 | 54 | ### [Resolve](Packages/com.quabug.one-shot-injection/OneShot.cs#L88) 55 | ``` c# 56 | container.Resolve(); 57 | container.Resolve(); 58 | container.Resolve>(); 59 | ``` 60 | 61 | ### [InjectAttribute](Packages/com.quabug.one-shot-injection/OneShot.cs#L291) 62 | ``` c# 63 | class Foo 64 | { 65 | public Foo() {} 66 | // mark a constructor to use on instantiate 67 | [Inject] public Foo(int value) {} 68 | 69 | [Inject] int IntValue; // field able to inject 70 | [Inject] float FloatValue { get; set; } // property albe to inject 71 | [Inject] void Init(int value) {} // method albe to inject 72 | } 73 | 74 | container.Register().Singleton().AsSelf(); 75 | var foo = container.Resolve(); // instantial `Foo` by `Foo(int value)` 76 | container.InjectAll(foo); // inject its fields, properteis and methods 77 | ``` 78 | 79 | ### [Label](Packages/com.quabug.one-shot-injection/OneShot.cs#L298) 80 | ``` c# 81 | class Foo {} 82 | interface TypedLabelFoo : ILabel {} // declare type-specific label, will throw on labeling other type 83 | interface AnyLabel : ILabel {} // declare generic-typed label, works on any types 84 | 85 | class Bar 86 | { 87 | public Bar( 88 | Foo foo, // un-labeled type 89 | [Inject(typeof(TypedLabelFoo))] Foo labeledFoo, // labeled type with type-specific label 90 | [Inject(typeof(AnyLabel<>))] Foo anyLabeledFoo, // labeled type 91 | [Inject(typeof(AnyLabel<>))] int anyLabeledInt // labeled type 92 | ) {} 93 | 94 | [Inject(typeof(AnyLabel<>))] Foo LabeledProperty { get; private set; } 95 | [Inject(typeof(FooLabel))] Foo LabeledField; 96 | } 97 | 98 | container.Register().AsSelf(typeof(TypedLabel)); // register typed label foo 99 | container.Register().With((123, typeof(AnyLabel<>)), (new Foo(), typeof(AnyLabel<>))).AsSelf(); // register additional-labeled instances 100 | ``` 101 | --------------------------------------------------------------------------------