diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1991c31 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,211 @@ + +[*] +charset = utf-8 +end_of_line = crlf +trim_trailing_whitespace = true +insert_final_newline = false +indent_style = space +indent_size = 4 + +# Microsoft .NET properties +csharp_preferred_modifier_order = public, protected, internal, private, static, extern, sealed, abstract, virtual, override, new, readonly, async, unsafe, volatile:warning +csharp_prefer_braces = true:warning +csharp_preserve_single_line_blocks = false +csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning +dotnet_naming_rule.constants_rule.import_to_resharper = as_predefined +dotnet_naming_rule.constants_rule.severity = warning +dotnet_naming_rule.constants_rule.style = upper_camel_case_style +dotnet_naming_rule.constants_rule.symbols = constants_symbols +dotnet_naming_rule.private_constants_rule.import_to_resharper = as_predefined +dotnet_naming_rule.private_constants_rule.severity = warning +dotnet_naming_rule.private_constants_rule.style = lower_camel_case_style +dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols +dotnet_naming_rule.private_instance_fields_rule.import_to_resharper = as_predefined +dotnet_naming_rule.private_instance_fields_rule.severity = warning +dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols +dotnet_naming_rule.private_static_fields_rule.import_to_resharper = as_predefined +dotnet_naming_rule.private_static_fields_rule.severity = warning +dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols +dotnet_naming_rule.private_static_readonly_rule.import_to_resharper = as_predefined +dotnet_naming_rule.private_static_readonly_rule.severity = warning +dotnet_naming_rule.private_static_readonly_rule.style = lower_camel_case_style +dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols +dotnet_naming_rule.public_fields_rule.import_to_resharper = as_predefined +dotnet_naming_rule.public_fields_rule.severity = warning +dotnet_naming_rule.public_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols +dotnet_naming_rule.static_readonly_rule.import_to_resharper = as_predefined +dotnet_naming_rule.static_readonly_rule.severity = warning +dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols +dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True +dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field +dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef +dotnet_naming_rule.unity_serialized_field_rule.severity = warning +dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style +dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols +dotnet_naming_rule.unity_serialized_field_rule_1.import_to_resharper = True +dotnet_naming_rule.unity_serialized_field_rule_1.resharper_description = Unity serialized field +dotnet_naming_rule.unity_serialized_field_rule_1.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef +dotnet_naming_rule.unity_serialized_field_rule_1.severity = warning +dotnet_naming_rule.unity_serialized_field_rule_1.style = lower_camel_case_style +dotnet_naming_rule.unity_serialized_field_rule_1.symbols = unity_serialized_field_symbols_1 +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case +dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.constants_symbols.applicable_kinds = field +dotnet_naming_symbols.constants_symbols.required_modifiers = const +dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field +dotnet_naming_symbols.private_constants_symbols.required_modifiers = const +dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly +dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = * +dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field +dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance +dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_accessibilities = * +dotnet_naming_symbols.unity_serialized_field_symbols_1.applicable_kinds = +dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_applicable_kinds = unity_serialised_field +dotnet_naming_symbols.unity_serialized_field_symbols_1.resharper_required_modifiers = instance +dotnet_separate_import_directive_groups = true +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:none +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:none +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = false:warning +dotnet_style_qualification_for_event = true:warning +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_property = true:warning +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning + +# ReSharper properties +resharper_accessor_owner_body = accessors_with_block_body +resharper_align_linq_query = true +resharper_align_multiline_argument = true +resharper_align_multiline_binary_expressions_chain = false +resharper_align_multiline_extends_list = true +resharper_align_multiline_for_stmt = true +resharper_align_multiline_parameter = true +resharper_align_multiple_declaration = true +resharper_align_multline_type_parameter_constrains = true +resharper_align_multline_type_parameter_list = true +resharper_align_tuple_components = true +resharper_autodetect_indent_settings = true +resharper_blank_lines_after_block_statements = 0 +resharper_blank_lines_around_single_line_auto_property = 1 +resharper_blank_lines_around_single_line_local_method = 1 +resharper_blank_lines_around_single_line_property = 1 +resharper_braces_redundant = true +resharper_csharp_align_first_arg_by_paren = true +resharper_csharp_allow_far_alignment = true +resharper_csharp_blank_lines_around_single_line_field = 1 +resharper_csharp_blank_lines_around_single_line_invocable = 1 +resharper_csharp_int_align_fix_in_adjacent = false +resharper_csharp_keep_blank_lines_in_code = 1 +resharper_csharp_keep_blank_lines_in_declarations = 1 +resharper_csharp_max_line_length = 0 +resharper_csharp_naming_rule.constants = AaBb +resharper_csharp_naming_rule.private_constants = aaBb +resharper_csharp_naming_rule.private_static_fields = aaBb +resharper_csharp_naming_rule.private_static_readonly = aaBb +resharper_csharp_naming_rule.static_readonly = AaBb +resharper_csharp_stick_comment = false +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_before_binary_opsign = true +resharper_csharp_wrap_extends_list_style = chop_if_long +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_enforce_line_ending_style = true +resharper_indent_nested_fixed_stmt = true +resharper_indent_nested_foreach_stmt = true +resharper_indent_nested_for_stmt = true +resharper_indent_nested_lock_stmt = true +resharper_indent_nested_usings_stmt = true +resharper_indent_nested_while_stmt = true +resharper_indent_preprocessor_region = no_indent +resharper_keep_existing_arrangement = false +resharper_max_array_initializer_elements_on_line = 1 +resharper_max_attribute_length_for_same_line = 0 +resharper_max_enum_members_on_line = 1 +resharper_max_initializer_elements_on_line = 1 +resharper_nested_ternary_style = expanded +resharper_object_creation_when_type_not_evident = target_typed +resharper_outdent_statement_labels = true +resharper_parentheses_non_obvious_operations = none, null_coalescing, conditional, conditional_or, conditional_and, bitwise, bitwise_inclusive_or, range, bitwise_exclusive_or, equality, relational, shift, arithmetic, additive, multiplicative, bitwise_and +resharper_parentheses_same_type_operations = true +resharper_place_attribute_on_same_line = false +resharper_place_expr_accessor_on_single_line = true +resharper_place_expr_method_on_single_line = true +resharper_place_expr_property_on_single_line = true +resharper_place_linq_into_on_new_line = false +resharper_place_simple_initializer_on_single_line = false +resharper_place_simple_property_pattern_on_single_line = false +resharper_show_autodetect_configure_formatting_tip = false +resharper_static_members_qualify_members = none, field, property, event, method +resharper_static_members_qualify_with = current_type +resharper_trailing_comma_in_multiline_lists = true +resharper_trailing_comma_in_singleline_lists = true +resharper_use_indent_from_vs = false +resharper_wrap_array_initializer_style = chop_always +resharper_wrap_chained_binary_expressions = chop_if_long +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_linq_expressions = chop_always +resharper_wrap_object_and_collection_initializer_style = chop_always +resharper_wrap_property_pattern = chop_always +resharper_wrap_text = false +resharper_xmldoc_allow_far_alignment = true +resharper_xmldoc_attribute_indent = align_by_first_attribute +resharper_xmldoc_keep_user_linebreaks = false +resharper_xmldoc_pi_attribute_style = on_single_line +resharper_xmldoc_space_before_self_closing = false +resharper_xmldoc_wrap_tags_and_pi = false + +# ReSharper inspection severities +resharper_arguments_style_anonymous_function_highlighting = warning +resharper_arguments_style_literal_highlighting = warning +resharper_arguments_style_named_expression_highlighting = warning +resharper_arguments_style_other_highlighting = warning +resharper_arguments_style_string_literal_highlighting = warning +resharper_arrange_accessor_owner_body_highlighting = warning +resharper_arrange_attributes_highlighting = warning +resharper_arrange_constructor_or_destructor_body_highlighting = warning +resharper_arrange_default_value_when_type_evident_highlighting = warning +resharper_arrange_default_value_when_type_not_evident_highlighting = warning +resharper_arrange_local_function_body_highlighting = warning +resharper_arrange_method_or_operator_body_highlighting = warning +resharper_arrange_missing_parentheses_highlighting = warning +resharper_arrange_object_creation_when_type_evident_highlighting = warning +resharper_arrange_object_creation_when_type_not_evident_highlighting = warning +resharper_arrange_redundant_parentheses_highlighting = warning +resharper_arrange_static_member_qualifier_highlighting = warning +resharper_arrange_trailing_comma_in_multiline_lists_highlighting = warning +resharper_arrange_trailing_comma_in_singleline_lists_highlighting = warning +resharper_arrange_var_keywords_in_deconstructing_declaration_highlighting = warning +resharper_member_can_be_made_static_local_highlighting = none +resharper_member_can_be_private_global_highlighting = none +resharper_parameter_hides_member_highlighting = none +resharper_suggest_discard_declaration_var_style_highlighting = warning +resharper_web_config_module_not_resolved_highlighting = warning +resharper_web_config_type_not_resolved_highlighting = warning +resharper_web_config_wrong_module_highlighting = warning + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 diff --git a/Mod.cs b/Mod.cs index 300278b..5dad554 100644 --- a/Mod.cs +++ b/Mod.cs @@ -58,8 +58,7 @@ private IEnumerable LoadAssemblies() string assembliesPath = $"{this.Meta.Directory}{System.IO.Path.DirectorySeparatorChar}Assemblies"; return System.IO.Directory.Exists(assembliesPath) - ? from assemblyPath in System.IO.Directory.GetFiles(assembliesPath, "*.dll", SearchOption.AllDirectories) - select Assembly.LoadFile(assemblyPath) + ? System.IO.Directory.GetFiles(assembliesPath, "*dll", SearchOption.AllDirectories).Select(Assembly.LoadFile) : Enumerable.Empty(); } @@ -73,10 +72,10 @@ select Assembly.LoadFile(assemblyPath) XmlDocument data = new(); data.InsertBefore(data.CreateXmlDeclaration("1.0", "UTF-8", null), data.DocumentElement); - (from document in documents - from node in document.Cast() - where node.NodeType is not XmlNodeType.XmlDeclaration - select node).ForEach(node => data.AppendChild(node)); + documents + .SelectMany(document => document.Cast()) + .Where(node => node.NodeType is not XmlNodeType.XmlDeclaration) + .ForEach(node => data.AppendChild(node)); return data; } @@ -250,8 +249,8 @@ public static Metadata Load(string directoryPath) private void IsValid() { // Check that the incompatible, load before, and load after lists don't have anything in common or contain the mod's own ID - bool invalidLoadOrder = this.Id.Yield() - .Concat(this.Incompatible) + bool invalidLoadOrder = this.Incompatible + .Prepend(this.Id) .Concat(this.Before) .Concat(this.After) .Indistinct() diff --git a/ModLoader.cs b/ModLoader.cs index 530656b..624f337 100644 --- a/ModLoader.cs +++ b/ModLoader.cs @@ -54,8 +54,9 @@ public static Mod LoadMod(string modDirectoryPath, bool executeAssemblies = true /// This method loads multiple s after sorting them according to the load order specified in their metadata. To load a individually without regard to its dependencies and load order, should be used. public static IEnumerable LoadMods(IEnumerable modDirectoryPaths, bool executeAssemblies = true) { - List mods = (from metadata in ModLoader.SortModMetadata(ModLoader.FilterModMetadata(ModLoader.LoadModMetadata(modDirectoryPaths))) - select new Mod(metadata)).ToList(); + List mods = ModLoader.SortModMetadata(ModLoader.FilterModMetadata(ModLoader.LoadModMetadata(modDirectoryPaths))) + .Select(metadata => new Mod(metadata)) + .ToList(); mods.ForEach(mod => ModLoader.loadedMods.Add(mod.Meta.Id, mod)); if (executeAssemblies) { @@ -67,15 +68,14 @@ public static IEnumerable LoadMods(IEnumerable modDirectoryPaths, b private static void StartupMod(Mod mod) { // Invoke all static methods annotated with [Startup] along with the supplied parameters (if any) - (from assembly in mod.Assemblies - from type in assembly.GetTypes() - from method in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public) - let attribute = method.GetCustomAttribute() - where attribute is not null - select (method, attribute)).ForEach(pair => pair.method.Invoke(null, pair.attribute.Parameters)); + mod.Assemblies + .SelectMany(assembly => assembly.GetTypes()) + .SelectMany(type => type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public)) + .Select(method => (method, method.GetCustomAttribute())) + .Where(pair => pair.Item2 is not null) + .ForEach(pair => pair.Item1.Invoke(null, pair.Item2.Parameters)); } - [MustUseReturnValue] private static Dictionary LoadModMetadata(IEnumerable modDirectories) { Dictionary loadedMetadata = new(); @@ -84,12 +84,10 @@ where attribute is not null Mod.Metadata metadata = Mod.Metadata.Load(modDirectory); // Fail if the metadata is incompatible with any of the loaded metadata (and vice-versa), or if the ID already exists - IEnumerable incompatibleMetadata = (from id in metadata.Incompatible - select loadedMetadata.GetValueOrDefault(id)) + IEnumerable incompatibleMetadata = metadata.Incompatible + .Select(id => loadedMetadata.GetValueOrDefault(id)) .NotNull() - .Concat(from loaded in loadedMetadata.Values - where loaded.Incompatible.Contains(metadata.Id) - select loaded); + .Concat(loadedMetadata.Values.Where(loaded => loaded.Incompatible.Contains(metadata.Id))); if (incompatibleMetadata.Any()) { Log.Error(new ModLoadException(metadata.Directory, "Incompatible with other loaded mods")); @@ -102,14 +100,14 @@ where loaded.Incompatible.Contains(metadata.Id) return loadedMetadata; } - [MustUseReturnValue] private static Dictionary FilterModMetadata(Dictionary loadedMetadata) { // If the dependencies of any metadata have not been loaded, remove that metadata and try again - foreach (Mod.Metadata metadata in from metadata in loadedMetadata.Values - where (from dependency in metadata.Dependencies - select loadedMetadata.TryGetValue(dependency, out _)).Any(dependency => !dependency) - select metadata) + IEnumerable invalidMetadata = loadedMetadata.Values + .Where(metadata => metadata.Dependencies + .Select(dependency => loadedMetadata.TryGetValue(dependency, out _)) + .Any(dependency => !dependency)); + foreach (Mod.Metadata metadata in invalidMetadata) { Log.Error(new ModLoadException(metadata.Directory, "Not all dependencies are loaded")); loadedMetadata.Remove(metadata.Id); @@ -118,7 +116,6 @@ select loadedMetadata.TryGetValue(dependency, out _)).Any(dependency => !depende return loadedMetadata; } - [MustUseReturnValue] private static IEnumerable SortModMetadata(Dictionary filteredMetadata) { // Create a graph of each metadata ID and the IDs of those that need to be loaded after it @@ -135,12 +132,11 @@ select loadedMetadata.TryGetValue(dependency, out _)).Any(dependency => !depende } // Topologically sort the dependency graph, removing cyclic dependencies if any - IEnumerable? sortedMetadataIds = dependencyGraph.Keys - .TopologicalSort(id => dependencyGraph.GetValueOrDefault(id) ?? Enumerable.Empty(), cyclic => - { - Log.Error(new ModLoadException(filteredMetadata[cyclic].Directory, "Cyclic dependencies with other mod(s)")); - filteredMetadata.Remove(cyclic); - }); + IEnumerable? sortedMetadataIds = dependencyGraph.Keys.TopologicalSort(id => dependencyGraph.GetValueOrDefault(id) ?? Enumerable.Empty(), cyclic => + { + Log.Error(new ModLoadException(filteredMetadata[cyclic].Directory, "Cyclic dependencies with other mod(s)")); + filteredMetadata.Remove(cyclic); + }); // If there is no valid topological sorting (cyclic dependencies detected), remove the cyclic metadata and try again return sortedMetadataIds? diff --git a/Modot.csproj b/Modot.csproj index 0d899c4..1a5d4c5 100644 --- a/Modot.csproj +++ b/Modot.csproj @@ -8,7 +8,7 @@ true true - 1.0.1 + 1.0.2 Modot Carnagion A mod loader and API for applications made using Godot, with the ability to load C# assemblies, XML data, and resource packs at runtime. diff --git a/README.md b/README.md index c064ace..7683112 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ A more detailed explanation of all features along with instructions on usage is Simply include the following lines in a Godot project's `.csproj` file (either by editing the file manually or letting an IDE install the package): ```xml - + ``` diff --git a/Utility/Extensions/DirectoryExtensions.cs b/Utility/Extensions/DirectoryExtensions.cs index 90c9ccf..5ed7fb9 100644 --- a/Utility/Extensions/DirectoryExtensions.cs +++ b/Utility/Extensions/DirectoryExtensions.cs @@ -68,7 +68,8 @@ public static void CopyContents(this Directory directory, string from, string to public static string[] GetFiles(this Directory directory, bool recursive = false) { return recursive - ? directory.GetDirectories(true) + ? directory + .GetDirectories(true) .SelectMany(path => { using Directory recursiveDirectory = new(); @@ -77,7 +78,8 @@ public static string[] GetFiles(this Directory directory, bool recursive = false }) .Concat(directory.GetElementsNonRecursive(true)) .ToArray() - : directory.GetElementsNonRecursive(true) + : directory + .GetElementsNonRecursive(true) .ToArray(); } @@ -106,15 +108,19 @@ public static string[] GetFiles(this Directory directory, bool recursive = false public static string[] GetDirectories(this Directory directory, bool recursive = false) { return recursive - ? directory.GetElementsNonRecursive(false) + ? directory + .GetElementsNonRecursive(false) .SelectMany(path => { using Directory recursiveDirectory = new(); recursiveDirectory.Open(path); - return recursiveDirectory.GetDirectories(true).Prepend(path); + return recursiveDirectory + .GetDirectories(true) + .Prepend(path); }) .ToArray() - : directory.GetElementsNonRecursive(false) + : directory + .GetElementsNonRecursive(false) .ToArray(); } diff --git a/Utility/Extensions/EnumerableExtensions.cs b/Utility/Extensions/EnumerableExtensions.cs index fb9d23b..4a29a2a 100644 --- a/Utility/Extensions/EnumerableExtensions.cs +++ b/Utility/Extensions/EnumerableExtensions.cs @@ -49,7 +49,8 @@ bool VisitDependencies(T t) return true; case false: states[t] = null; - bool dependenciesValid = dependencies.Invoke(t) + bool dependenciesValid = dependencies + .Invoke(t) .Select(VisitDependencies) .All(boolean => boolean); if (!dependenciesValid)