From b9c01c61d5ddb41cd2ebf33e17a0d387bb13e9c7 Mon Sep 17 00:00:00 2001 From: Paul Hirch Date: Wed, 8 May 2024 02:45:27 +0200 Subject: [PATCH] update --- .editorconfig | 231 ++++++++++++++++++ Assets/Asset.cs | 51 +++- Assets/AssetCollection.cs | 57 +---- Assets/AssetCreateInfo.cs | 8 + Assets/AssetLibary.cs | 82 +------ Assets/AssetLibaryContent.cs | 117 +++++++++ Assets/AssetLibaryLoader.cs | 114 ++++++--- Assets/GroundCoverAsset.cs | 21 +- Assets/GroundCoverBuilder.cs | 46 ++++ Assets/GroundCoverInstanceAsset.cs | 19 -- .../{LevelPreset.cs => LevelObjectsAsset.cs} | 12 +- Assets/MaterialAsset.cs | 10 +- ...aterialAsset.cs => ObjectMaterialAsset.cs} | 8 +- ...terialAsset.cs => TerrainMaterialAsset.cs} | 13 +- Collections/IKeyed.cs | 12 + Collections/KeyedCollection.cs | 105 ++++++++ Embedded/InvalidPreview.png | Bin 944 -> 946 bytes GUI/AssetViewBox.cs | 127 +++++++--- GUI/ContentManager.Designer.cs | 70 ++++-- GUI/ContentManager.cs | 14 +- GUI/ExceptionBox.cs | 15 ++ GUI/LabledTextbox.Designer.cs | 35 ++- GUI/LevelSettings.Designer.cs | 35 ++- GUI/LevelSettings.cs | 12 +- GUI/MainForm.Designer.cs | 52 ++-- GUI/MainForm.cs | 49 ++-- GUI/TerrainSettings.Designer.cs | 128 ++++++---- GUI/TerrainSettings.cs | 38 ++- IO/Resources/Resource.cs | 7 +- IO/Resources/ResourceCollection.cs | 43 ++++ IO/Resources/ResourceManager.cs | 72 +----- IO/Resources/SolidColorNames.cs | 4 + IO/TerrainV9Serializer.cs | 21 +- Level.cs | 39 ++- LevelInfo.cs | 4 +- LevelTemplateCreator.sln | 7 +- Program.cs | 39 ++- .../PublishProfiles/FolderProfile.pubxml | 18 ++ .../PublishProfiles/FolderProfile.pubxml.user | 10 + README.md | 47 +++- SceneTree/Art/ForestItemData.cs | 19 ++ SceneTree/Art/Material.cs | 2 +- SceneTree/Art/MaterialLibary.cs | 36 ++- SceneTree/Art/ObjectMaterial.cs | 4 +- SceneTree/Art/ObjectMaterialLibary.cs | 22 ++ ...rrainPbrMaterial.cs => TerrainMaterial.cs} | 69 ++++-- SceneTree/Art/TerrainMaterialLibary.cs | 39 +++ ...ureSet.cs => TerrainMaterialTextureSet.cs} | 4 +- SceneTree/JsonDictProperty.cs | 33 ++- SceneTree/JsonDictWrapper.cs | 35 ++- SceneTree/Main/GroundCover.cs | 24 +- SceneTree/Main/GroundCoverInstance.cs | 39 ++- SceneTree/Main/SimGroup.cs | 33 +-- SceneTree/Main/SimGroupMissionGroup.cs | 5 +- SceneTree/Main/SpawnSphere.cs | 56 +++++ SceneTree/Main/TerrainBlock.cs | 2 +- TerrainInfo.cs | 5 +- 57 files changed, 1595 insertions(+), 624 deletions(-) create mode 100644 .editorconfig create mode 100644 Assets/AssetCreateInfo.cs create mode 100644 Assets/AssetLibaryContent.cs create mode 100644 Assets/GroundCoverBuilder.cs delete mode 100644 Assets/GroundCoverInstanceAsset.cs rename Assets/{LevelPreset.cs => LevelObjectsAsset.cs} (85%) rename Assets/{ObjectPbrMaterialAsset.cs => ObjectMaterialAsset.cs} (50%) rename Assets/{TerrainPbrMaterialAsset.cs => TerrainMaterialAsset.cs} (74%) create mode 100644 Collections/IKeyed.cs create mode 100644 Collections/KeyedCollection.cs create mode 100644 GUI/ExceptionBox.cs create mode 100644 IO/Resources/ResourceCollection.cs create mode 100644 Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Properties/PublishProfiles/FolderProfile.pubxml.user create mode 100644 SceneTree/Art/ForestItemData.cs create mode 100644 SceneTree/Art/ObjectMaterialLibary.cs rename SceneTree/Art/{TerrainPbrMaterial.cs => TerrainMaterial.cs} (71%) create mode 100644 SceneTree/Art/TerrainMaterialLibary.cs rename SceneTree/Art/{TerrainPbrMaterialTextureSet.cs => TerrainMaterialTextureSet.cs} (84%) create mode 100644 SceneTree/Main/SpawnSphere.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..41dcecd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,231 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = file_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_primary_constructors = true +csharp_style_prefer_top_level_statements = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/Assets/Asset.cs b/Assets/Asset.cs index a2c4117..a35a645 100644 --- a/Assets/Asset.cs +++ b/Assets/Asset.cs @@ -1,36 +1,47 @@ -using LevelTemplateCreator.IO.Resources; +using LevelTemplateCreator.Collections; +using LevelTemplateCreator.IO.Resources; using LevelTemplateCreator.SceneTree; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Linq; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; namespace LevelTemplateCreator.Assets; -abstract class Asset +abstract class Asset : IKeyed { - public string Name { get; set; } = string.Empty; + string IKeyed.Key => Object.Name.Value; + + public string DisplayName { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; - public Image Preview { get; set; } + public Image Preview { get; } public string SourceFile { get; } + public string Namespace { get; } + public JsonDictWrapper Object { get; } - public Asset(JsonDictWrapper obj, string source) + public Asset(JsonDictWrapper obj, AssetCreateInfo info) { Object = obj; - SourceFile = source; + SourceFile = info.SourceFile; + Namespace = info.Namespace; + + obj.ApplyNamespace(Namespace); if (obj.TryPopValue("preview", out string path)) { try { - using var stream = ResourceManager.Parse(path, source).OpenStream(); + using var stream = ResourceManager.ParseRelative(path, SourceFile).OpenStream(); var bitmap = new Bitmap(stream); Preview = bitmap; } @@ -44,10 +55,36 @@ public Asset(JsonDictWrapper obj, string source) Preview = Properties.Resources.NoPreview; } + if (obj.TryPopValue("displayName", out string name)) + { + DisplayName = name; + } + else if (obj.Name.Exists) + { + DisplayName = Object.Name.Value; + } + if (obj.TryPopValue("description", out string desc)) { Description = desc; } } + public virtual JsonDictWrapper GetCopy() + { + return Object.Copy(); + } +} + +abstract class Asset : Asset where T : JsonDictWrapper +{ + public new T Object => (T)base.Object; + + public Asset(T obj, AssetCreateInfo info) : base(obj, info) { } + + public override T GetCopy() + { + return (T)Object.Copy(); + } } + diff --git a/Assets/AssetCollection.cs b/Assets/AssetCollection.cs index d067307..b43fe39 100644 --- a/Assets/AssetCollection.cs +++ b/Assets/AssetCollection.cs @@ -1,4 +1,5 @@ -using System; +using LevelTemplateCreator.Collections; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -7,56 +8,4 @@ namespace LevelTemplateCreator.Assets; -internal class AssetCollection : ICollection where T : Asset -{ - Dictionary assets = new Dictionary(); - - public int Count => assets.Count; - - public bool IsReadOnly => false; - - public void Add(T item) - { - assets[item.Name] = item; - } - - public void Clear() - { - assets.Clear(); - } - - public T this[string key] => assets[key]; - - - public bool ConatinsKey(string key) => assets.ContainsKey(key); - - public bool TryGetValue(string key, out T value) - { - return assets.TryGetValue(key, out value!); - } - - public bool Contains(T item) - { - return assets.ContainsKey(item.Name); - } - - public void CopyTo(T[] array, int arrayIndex) - { - assets.Values.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return assets.Values.GetEnumerator(); - } - - public bool Remove(T item) - { - return assets.Remove(item.Name); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return assets.Values.GetEnumerator(); - } -} +internal class AssetCollection : KeyedCollection where T : Asset { } diff --git a/Assets/AssetCreateInfo.cs b/Assets/AssetCreateInfo.cs new file mode 100644 index 0000000..21881ed --- /dev/null +++ b/Assets/AssetCreateInfo.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.Assets; +record AssetCreateInfo(string SourceFile, string Namespace); \ No newline at end of file diff --git a/Assets/AssetLibary.cs b/Assets/AssetLibary.cs index 6f22739..4d02b10 100644 --- a/Assets/AssetLibary.cs +++ b/Assets/AssetLibary.cs @@ -1,27 +1,23 @@ -using LevelTemplateCreator.IO; +using LevelTemplateCreator.Collections; +using LevelTemplateCreator.IO; using LevelTemplateCreator.IO.Resources; using LevelTemplateCreator.SceneTree; +using LevelTemplateCreator.SceneTree.Art; using LevelTemplateCreator.SceneTree.Main; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; namespace LevelTemplateCreator.Assets; internal class AssetLibary { - public AssetCollection LevelPresets { get; } + public AssetCollection LevelPresets { get; } - public AssetCollection TerrainMaterials { get; } + public AssetCollection TerrainMaterials { get; } - public AssetCollection ObjectMaterials { get; } + public AssetCollection ObjectMaterials { get; } public AssetCollection GroundCoverDefinitions { get; } - public AssetCollection GroundCoverInstances { get; } + public List GroundCoverInstances { get; } public Bitmap? Preview { get; set; } @@ -36,31 +32,6 @@ public AssetLibary() GroundCoverInstances = new(); } - public void Add(IEnumerable assets) - { - foreach (var asset in assets) - { - Add(asset); - } - } - - public void Add(Asset asset) - { - switch (asset) - { - case LevelPreset preset: - LevelPresets.Add(preset); - break; - - case TerrainPbrMaterialAsset material: - TerrainMaterials.Add(material); - break; - - default: - throw new ArgumentException(); - } - } - public void Clear() { LevelPresets.Clear(); @@ -74,47 +45,16 @@ public void SeperateGroundCoverInstances() { foreach (var item in GroundCoverDefinitions) { - AddGroundCoverInstances(GroundCoverInstance.PopFromGroundcover(item.GroundCover), item.SourceFile); - } - - foreach (var item in TerrainMaterials) { - AddGroundCoverInstances(GroundCoverInstance.PopFromMaterial(item.Material), item.SourceFile); + AddGroundCoverInstances(GroundCoverInstance.PopFromGroundcover(item.GroundCover), item); } } - void AddGroundCoverInstances(GroundCoverInstance[] instances, string source) + void AddGroundCoverInstances(GroundCoverInstance[] instances, Asset parent) { foreach (var item in instances) { - var asset = new GroundCoverInstanceAsset(item, source); - GroundCoverInstances.Add(asset); - } - } - - public void GetGroundCoverInstances(AssetCollection filter, AssetCollection target) - { - foreach (var item in GroundCoverInstances) - { - if (filter.ConatinsKey(item.Instance.Layer.Value)) - { - target.Add(item); - } - } - } - - public void CreateGroundCoverObjects(AssetCollection instances) - { - - } - - public void GetMaterials(AssetCollection filter, AssetCollection target) - { - foreach (var item in GroundCoverInstances) - { - if (filter.ConatinsKey(item.Instance.Layer.Value)) - { - //target.Add(item); - } + item.ApplyNamespace(parent.Namespace); + GroundCoverInstances.Add(item); } } diff --git a/Assets/AssetLibaryContent.cs b/Assets/AssetLibaryContent.cs new file mode 100644 index 0000000..c5f4ac8 --- /dev/null +++ b/Assets/AssetLibaryContent.cs @@ -0,0 +1,117 @@ +using LevelTemplateCreator.Collections; +using LevelTemplateCreator.SceneTree.Main; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.Assets; +internal class AssetLibaryContent : AssetLibary +{ + public List GroundCoverObjects { get; } + + public AssetLibaryContent() + { + GroundCoverObjects = new List(); + } + + public void Add(IEnumerable assets) + { + foreach (var asset in assets) + { + Add(asset); + } + } + + public void Add(Asset asset) + { + switch (asset) + { + case LevelObjectsAsset preset: + LevelPresets.Add(preset); + break; + + case TerrainMaterialAsset material: + TerrainMaterials.Add(material); + break; + + default: + throw new ArgumentException($"{asset.GetType().Name} not supported."); + } + } + + public void GetAssets(AssetLibary libary) + { + GetGroundCoverInstances(libary); + GetGroundCoverDefinitions(libary); + CreateGroundCoverObjects(); + GetMaterials(libary); + } + + void GetGroundCoverInstances(AssetLibary libary) + { + foreach (var item in libary.GroundCoverInstances) + { + if (TerrainMaterials.ContainsKey(item.Layer.Value)) + { + GroundCoverInstances.Add(item); + } + } + } + + void GetGroundCoverDefinitions(AssetLibary libary) + { + foreach (var item in GroundCoverInstances) + { + var key = item.Parent.Value; + + if (libary.GroundCoverDefinitions.TryGetValue(key, out var obj)) + { + GroundCoverDefinitions.Add(obj); + } + } + } + + void CreateGroundCoverObjects() + { + KeyedCollection builders = new(); + + foreach (var item in GroundCoverDefinitions) + { + var builder = new GroundCoverBuilder(item); + builders.Add(builder); + } + + + foreach (var item in GroundCoverInstances) + { + var parent = item.Parent.Value; + + if (builders.TryGetValue(parent, out var ass)) + { + ass.AddInstance(item); + } + } + + GroundCoverObjects.Clear(); + + foreach (var item in builders) + { + GroundCoverObjects.Add(item.Create()); + } + } + + void GetMaterials(AssetLibary libary) + { + foreach (var item in GroundCoverDefinitions) + { + var key = item.GroundCover.Material.Value; + + if (libary.ObjectMaterials.TryGetValue(key, out var obj)) + { + ObjectMaterials.Add(obj); + } + } + } +} diff --git a/Assets/AssetLibaryLoader.cs b/Assets/AssetLibaryLoader.cs index dffb7b4..bc6bcbf 100644 --- a/Assets/AssetLibaryLoader.cs +++ b/Assets/AssetLibaryLoader.cs @@ -1,11 +1,7 @@ using LevelTemplateCreator.IO; using LevelTemplateCreator.SceneTree; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; +using LevelTemplateCreator.SceneTree.Art; +using LevelTemplateCreator.SceneTree.Main; namespace LevelTemplateCreator.Assets; @@ -13,13 +9,17 @@ internal class AssetLibaryLoader { public record class Error(string File, Exception Exception); - public int MaxError { get; set; } = 10; + public bool Debug { get; set; } + + public int MaxError { get; set; } = 50; public List Errors { get; } public AssetLibary Libary { get; } - string currentFile = string.Empty; + string _currentFile = string.Empty; + + string _currentNamespace = ""; public AssetLibaryLoader(AssetLibary libary) { @@ -27,16 +27,23 @@ public AssetLibaryLoader(AssetLibary libary) Errors = new List(); } + void LogException(Exception e) + { + Errors.Add(new Error(_currentFile, e)); + } + public void LoadDirectory(string path) { + LoadDirectory(path, string.Empty); + } + + public void LoadDirectory(string path, string @namespace) + { + _currentNamespace = @namespace; + if (Errors.Count > MaxError) return; - foreach (var dir in Directory.EnumerateDirectories(path)) - { - LoadDirectory(dir); - } - foreach (var file in Directory.EnumerateFiles(path)) { var ext = Path.GetExtension(file).ToLower(); @@ -48,11 +55,24 @@ public void LoadDirectory(string path) } catch (Exception e) { - Errors.Add(new Error(file, e)); + LogException(e); + if (Debug) + throw; } } } + + + foreach (var dir in Directory.EnumerateDirectories(path)) + { + var name = Path.GetFileName(dir); + + var newNamespace = @namespace + name + "_"; + + LoadDirectory(dir, newNamespace); + } + var previewPath = Path.Combine(path, "preview.png"); if (File.Exists(previewPath)) { @@ -65,7 +85,7 @@ public void LoadDirectory(string path) public void LoadFile(string path) { - currentFile = path; + _currentFile = path; using var stream = new FileStream(path, FileMode.Open, FileAccess.Read); Deserialize(stream); } @@ -73,61 +93,81 @@ public void LoadFile(string path) void Deserialize(Stream stream) { var dict = JsonDictSerializer.Deserialize(stream); + ParseObject(dict); + } - var item = new JsonDictWrapper(dict); + void ParseObject(JsonDict dict) + { + if (!dict.TryGetValue("class", out var classObj)) + { + throw new Exception("no class"); + } + var className = (string)classObj; - ParseObject(item); + try + { + ParseObject(dict, className); + } + catch (Exception e) + { + LogException(e); + if (Debug) + throw; + } } - void ParseObject(JsonDictWrapper item) + void ParseObject(JsonDict dict, string className) { - switch (item.Class.Value) + var createInfo = new AssetCreateInfo(_currentFile, _currentNamespace); + + switch (className) { case JsonDictSerializer.ArrayClassName: { - ParseArray(item); + ParseArray(dict); break; } - case LevelPreset.ClassName: + case LevelObjectsAsset.ClassName: { - var preset = new LevelPreset(item, currentFile); - Libary.LevelPresets.Add(preset); + var obj = new JsonDictWrapper(dict); + var asset = new LevelObjectsAsset(obj, createInfo); + Libary.LevelPresets.Add(asset); break; } - case TerrainPbrMaterialAsset.ClassName: + case TerrainMaterialAsset.ClassName: { - var material = new TerrainPbrMaterialAsset(item, currentFile); - //material.Material.IndexTextures(Libary.TextureFiles, currentFile); - Libary.TerrainMaterials.Add(material); + var obj = new TerrainMaterial(dict); + var asset = new TerrainMaterialAsset(obj, createInfo); + Libary.TerrainMaterials.Add(asset); break; } - case ObjectPbrMaterialAsset.ClassName: + case ObjectMaterialAsset.ClassName: { - var material = new ObjectPbrMaterialAsset(item, currentFile); - Libary.ObjectMaterials.Add(material); + var obj = new ObjectMaterial(dict); + var asset = new ObjectMaterialAsset(obj, createInfo); + Libary.ObjectMaterials.Add(asset); break; } case GroundCoverAsset.ClassName: { - var groundcover = new GroundCoverAsset(item, currentFile); - Libary.GroundCoverDefinitions.Add(groundcover); + var obj = new GroundCover(dict); + var asset = new GroundCoverAsset(obj, createInfo); + Libary.GroundCoverDefinitions.Add(asset); break; } default: { - throw new Exception($"Unsupported class {item.Class}."); + throw new Exception($"Unsupported class {className}."); } } } - void ParseArray(JsonDictWrapper array) + void ParseArray(JsonDict array) { var items = (JsonDict[])array["items"]; foreach (var item in items) { - var si = new JsonDictWrapper(item); - - ParseObject(si); + ParseObject(item); } } diff --git a/Assets/GroundCoverAsset.cs b/Assets/GroundCoverAsset.cs index c266632..08ea25c 100644 --- a/Assets/GroundCoverAsset.cs +++ b/Assets/GroundCoverAsset.cs @@ -1,26 +1,13 @@ using LevelTemplateCreator.SceneTree; using LevelTemplateCreator.SceneTree.Main; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace LevelTemplateCreator.Assets; -internal class GroundCoverAsset : Asset +internal class GroundCoverAsset : Asset { - public const string ClassName = "GroundCover"; + public const string ClassName = GroundCover.ClassName; - public GroundCover GroundCover { get; } + public GroundCover GroundCover => Object; - public GroundCoverAsset(JsonDictWrapper item, string file) : base(item, file) - { - GroundCover = new GroundCover(item.Dict); - } - - public void CreateNew(AssetCollection instances) - { - - } + public GroundCoverAsset(GroundCover item, AssetCreateInfo info) : base(item, info) { } } diff --git a/Assets/GroundCoverBuilder.cs b/Assets/GroundCoverBuilder.cs new file mode 100644 index 0000000..0b7817f --- /dev/null +++ b/Assets/GroundCoverBuilder.cs @@ -0,0 +1,46 @@ +using LevelTemplateCreator.Collections; +using LevelTemplateCreator.SceneTree.Main; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.Assets; +internal class GroundCoverBuilder : IKeyed +{ + GroundCoverAsset _groundCover; + + List _instances; + + string IKeyed.Key => _groundCover.Object.Name.Value; + + public GroundCoverBuilder(GroundCoverAsset groundCover) + { + _groundCover = groundCover; + _instances = new List(); + } + + public void AddInstance(GroundCoverInstance instance) + { + var copy = instance.Copy(); + copy.Parent.Remove(); + _instances.Add(copy); + } + + public GroundCover Create() + { + var copy = _groundCover.GetCopy(); + + var array = new JsonDict[8]; + + for (int i = 0; i < 8; i++) + { + array[i] = i < _instances.Count ? _instances[i].Dict : new JsonDict(); + } + + copy.Types.Value = array; + + return copy; + } +} diff --git a/Assets/GroundCoverInstanceAsset.cs b/Assets/GroundCoverInstanceAsset.cs deleted file mode 100644 index af316f3..0000000 --- a/Assets/GroundCoverInstanceAsset.cs +++ /dev/null @@ -1,19 +0,0 @@ -using LevelTemplateCreator.SceneTree; -using LevelTemplateCreator.SceneTree.Main; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LevelTemplateCreator.Assets; - -internal class GroundCoverInstanceAsset : Asset -{ - public GroundCoverInstance Instance { get; } - - public GroundCoverInstanceAsset(JsonDictWrapper obj, string source) : base(obj, source) - { - Instance = new GroundCoverInstance(obj.Dict); - } -} diff --git a/Assets/LevelPreset.cs b/Assets/LevelObjectsAsset.cs similarity index 85% rename from Assets/LevelPreset.cs rename to Assets/LevelObjectsAsset.cs index 227953d..8940558 100644 --- a/Assets/LevelPreset.cs +++ b/Assets/LevelObjectsAsset.cs @@ -9,18 +9,17 @@ namespace LevelTemplateCreator.Assets; -internal class LevelPreset : Asset +internal class LevelObjectsAsset : Asset { - public const string ClassName = "LevelPreset"; + public const string ClassName = "LevelObjects"; + Collection Items; - public LevelPreset(JsonDictWrapper data, string file) : base(data, file) + public LevelObjectsAsset(JsonDictWrapper data, AssetCreateInfo info) : base(data, info) { Items = new Collection(); - Name = data.Name.Value; - var rawitems = (JsonDict[])data["items"]; foreach (var rawitem in rawitems) @@ -52,6 +51,7 @@ public void Apply(SimGroupLevelObject group) case "LevelInfo": group.Infos.Items.Add(item); break; + case "Forest": case "ForestWindEmitter": group.Vegatation.Items.Add(item); break; @@ -64,6 +64,6 @@ public void Apply(SimGroupLevelObject group) public override string ToString() { - return Name; + return DisplayName; } } \ No newline at end of file diff --git a/Assets/MaterialAsset.cs b/Assets/MaterialAsset.cs index 4a93194..8ed2a04 100644 --- a/Assets/MaterialAsset.cs +++ b/Assets/MaterialAsset.cs @@ -8,12 +8,10 @@ namespace LevelTemplateCreator.Assets; -abstract class MaterialAsset : Asset +abstract class MaterialAsset : Asset where T : Material { - public Material Material { get; } + public T Material => Object; - protected MaterialAsset(JsonDictWrapper obj, string source, Material material) : base(obj, source) - { - Material = material; - } + protected MaterialAsset(T obj, AssetCreateInfo info) : base(obj, info) + { } } diff --git a/Assets/ObjectPbrMaterialAsset.cs b/Assets/ObjectMaterialAsset.cs similarity index 50% rename from Assets/ObjectPbrMaterialAsset.cs rename to Assets/ObjectMaterialAsset.cs index d639201..6eecce7 100644 --- a/Assets/ObjectPbrMaterialAsset.cs +++ b/Assets/ObjectMaterialAsset.cs @@ -8,13 +8,11 @@ namespace LevelTemplateCreator.Assets; -internal class ObjectPbrMaterialAsset : MaterialAsset +internal class ObjectMaterialAsset : MaterialAsset { - public const string ClassName = "Material"; + public const string ClassName = ObjectMaterial.ClassName; - public new ObjectMaterial Material => (ObjectMaterial)base.Material; - - public ObjectPbrMaterialAsset(JsonDictWrapper item, string source) : base(item, source, new ObjectMaterial(item.Dict)) + public ObjectMaterialAsset(ObjectMaterial item, AssetCreateInfo info) : base(item, info) { //Material = new ObjectMaterial(item.Dict); } diff --git a/Assets/TerrainPbrMaterialAsset.cs b/Assets/TerrainMaterialAsset.cs similarity index 74% rename from Assets/TerrainPbrMaterialAsset.cs rename to Assets/TerrainMaterialAsset.cs index 8bd4e2c..2b2a051 100644 --- a/Assets/TerrainPbrMaterialAsset.cs +++ b/Assets/TerrainMaterialAsset.cs @@ -9,16 +9,13 @@ namespace LevelTemplateCreator.Assets; -internal class TerrainPbrMaterialAsset : MaterialAsset +internal class TerrainMaterialAsset : MaterialAsset { - public const string ClassName = "TerrainMaterial"; - - - public new TerrainPbrMaterial Material => (TerrainPbrMaterial)base.Material; + public const string ClassName = TerrainMaterial.ClassName; public float SquareSize { get; } - public TerrainPbrMaterialAsset(JsonDictWrapper item, string file) : base(item, file, new TerrainPbrMaterial(item.Dict)) + public TerrainMaterialAsset(TerrainMaterial item, AssetCreateInfo info) : base(item, info) { Material.TryPopValue("squareSize", out float squareSize, 1); SquareSize = squareSize; @@ -28,10 +25,6 @@ internal class TerrainPbrMaterialAsset : MaterialAsset Material.InternalName.Value = Material.Name.Value; } - Material.CreatePersistentId(); - - Name = Material.InternalName.Value; - SetLayerIfEmpty(Material.AmbientOcclusion.Base, SolidColorNames.BaseAmbientOcclusion); SetLayerIfEmpty(Material.Normal.Base, SolidColorNames.BaseNormal); SetLayerIfEmpty(Material.Height.Base, SolidColorNames.BaseHeight); diff --git a/Collections/IKeyed.cs b/Collections/IKeyed.cs new file mode 100644 index 0000000..666368f --- /dev/null +++ b/Collections/IKeyed.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.Collections; + +internal interface IKeyed +{ + public string? Key { get; } +} diff --git a/Collections/KeyedCollection.cs b/Collections/KeyedCollection.cs new file mode 100644 index 0000000..5313411 --- /dev/null +++ b/Collections/KeyedCollection.cs @@ -0,0 +1,105 @@ +using LevelTemplateCreator.Assets; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LevelTemplateCreator.Collections; + +internal class KeyedCollection : ICollection where T : class, IKeyed +{ + readonly Dictionary _dict; + + public KeyedCollection() + { + _dict = new Dictionary(); + } + + public int Count => _dict.Count; + + public bool IsReadOnly => false; + + public Dictionary.KeyCollection Keys => _dict.Keys; + + string GetKey(T item) + { + string? key = item.Key; + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"Item has no key."); + } + return key; + } + + public void Add(T item) + { + var key = GetKey(item); + + if (TryGetValue(key, out T old)) + { + if (old == item) + { + return; + } + throw new ArgumentException($"A item with the key '{key}' is already in the collection."); + } + _dict[key] = item; + } + + public void Add(params T[] items) + { + foreach (var item in items) + { + Add(item); + } + } + + public bool TryGetValue(string key, out T value) + { + return _dict.TryGetValue(key, out value!); + } + + public void Clear() + { + _dict.Clear(); + } + + public bool ContainsKey(string key) => _dict.ContainsKey(key); + + public bool Contains(T item) + { + var key = GetKey(item); + return _dict.ContainsKey(key); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _dict.Values.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _dict.Values.GetEnumerator(); + } + + public bool Remove(T item) + { + var key = GetKey(item); + + if (!_dict.Remove(key, out var value)) + return false; + + if (item != value) + throw new ArgumentException(); + + return true; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} diff --git a/Embedded/InvalidPreview.png b/Embedded/InvalidPreview.png index 72fc3572eeb9f7a1d4039de3f6f97b085337f39a..5755372de76e19a91022dad6354db0b5ab4d4d14 100644 GIT binary patch delta 368 zcmV-$0gwK$2eJpS(E)!47c?Ri*MndH00F^CL_t(|+U?lwje;-$fZ_AP46NWX&f+k) zohx*T`_aUZ(v}J>{P1~miCz>befSEu$K&y%>-seX*EYqMd7jP1$%POc0Zu^xu3GW) z^@@L`k4j5jINE{NfX&q}|NXn)kFPlXNZ+km{#utoo_7&$oUDIyw(7`Q-plqK?YIq} z`tEMa%}(C8Y)R>BM-G%YjP)JQ+r1RGUNE zJ@p*`vTI8AxRWoQ*&X)%KAE+~!4JJ1nEGyi>0m#&3y(NiufLfc{EiiUw2i0Uh8~># zakosp7T{iEllQ>?LdSRGS<(aSyHUdh1V1i&WNCIa8Gm?-D?i6Nye6TT%3*&lby z)NAn_SN>ak7*{cW6p_6Rt(^GQelWzkUA-=pRzJw6Wg(Kh_`v-o1>Ofh1hQj~=002ov JPDHLkV1gzWzE1!E diff --git a/GUI/AssetViewBox.cs b/GUI/AssetViewBox.cs index ae1379e..ab5c4db 100644 --- a/GUI/AssetViewBox.cs +++ b/GUI/AssetViewBox.cs @@ -15,23 +15,45 @@ namespace LevelTemplateCreator; internal class AssetViewBox : Control { + readonly List _visibleItems; + + List _itemsPtr; + + int _hiddenCount = 0; + + string? _filter = null; + + public string? Filter + { + get => _filter; set + { + _filter = value; + ItemsChanged(); + } + } + public List Items { get; } + public int ItemHeight { get; set; } public int Position { get; set; } - public int MaxPosition => Items.Count * ItemHeight; + public int MaxPosition => _itemsPtr.Count * ItemHeight; public int HoveredIndex { get; private set; } public VScrollBar ScrollBar { get; } - public Action OnItemClick { get; set; } + public Action? OnItemClick { get; set; } public AssetViewBox() { Items = new List(); + _visibleItems = new List(); + + _itemsPtr = Items; + ItemHeight = 128; DoubleBuffered = true; @@ -49,23 +71,34 @@ public AssetViewBox() public void ItemsChanged() { - ScrollBar.Maximum = MaxPosition + ScrollBar.LargeChange - 1; - Items.Sort((x, y) => x.Name.CompareTo(y.Name)); - - Invalidate(); - } + if (string.IsNullOrEmpty(_filter)) + { + _itemsPtr = Items; + _hiddenCount = 0; + } + else + { + var filter = _filter.ToLower(); - protected override void OnPaint(PaintEventArgs e) - { - base.OnPaint(e); + _visibleItems.Clear(); - var g = e.Graphics; + foreach (var item in Items) + { + if (item.DisplayName.ToLower().Contains(_filter.ToLower())) + { + _visibleItems.Add(item); + } + } - for (var i = 0; i < Items.Count; i++) - { - var asset = Items[i]; - DrawItem(g, asset, i); + _hiddenCount = Items.Count - _visibleItems.Count; + _itemsPtr = _visibleItems; } + + ScrollBar.Maximum = MaxPosition + ScrollBar.LargeChange - 1; + Items.Sort((x, y) => x.DisplayName.CompareTo(y.DisplayName)); + + + Invalidate(); } protected override void OnMouseWheel(MouseEventArgs e) @@ -88,29 +121,33 @@ protected override void OnMouseWheel(MouseEventArgs e) Invalidate(); } - protected override void OnMouseClick(MouseEventArgs e) + protected override void OnMouseDown(MouseEventArgs e) { - base.OnMouseClick(e); + base.OnMouseDown(e); if (HoveredIndex < 0) return; - if (HoveredIndex > Items.Count - 1) + if (HoveredIndex > _itemsPtr.Count - 1) return; if (OnItemClick == null) return; - OnItemClick(Items[HoveredIndex]); + OnItemClick(_itemsPtr[HoveredIndex]); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); - HoveredIndex = (e.Location.Y + Position) / ItemHeight; + int index = (e.Location.Y + Position) / ItemHeight; - Invalidate(); + if (HoveredIndex != index) + { + HoveredIndex = index; + Invalidate(); + } } protected override void OnMouseLeave(EventArgs e) @@ -122,18 +159,38 @@ protected override void OnMouseLeave(EventArgs e) Invalidate(); } + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + var g = e.Graphics; + + int pos = 0; + for (var i = 0; i < _itemsPtr.Count; i++) + { + var asset = _itemsPtr[i]; + DrawItem(g, asset, i, pos++); + } + + DrawHidden(g); + } + Rectangle GetBounds(int index) { return new Rectangle(0, ItemHeight * index - Position, ClientSize.Width, ItemHeight); } - - void DrawItem(Graphics g, Asset item, int index) + void DrawItem(Graphics g, Asset item, int index, int position) { - - var brush = new SolidBrush(Color.Black); + var bounds = GetBounds(position); - var bounds = GetBounds(index); + if (bounds.Y + bounds.Height < 0) + return; + + if (bounds.Y > ClientSize.Height) + return; + + var brush = new SolidBrush(Color.Black); var boundsPreview = new Rectangle(bounds.X, bounds.Y, bounds.Height, bounds.Height); @@ -153,9 +210,9 @@ void DrawItem(Graphics g, Asset item, int index) } var sb = new StringBuilder(); - if (!string.IsNullOrEmpty(item.Name)) + if (!string.IsNullOrEmpty(item.DisplayName)) { - sb.AppendLine(item.Name); + sb.AppendLine(item.DisplayName); } if (!string.IsNullOrEmpty(item.Description)) { @@ -178,7 +235,17 @@ void DrawItem(Graphics g, Asset item, int index) var bru = new SolidBrush(Color.FromArgb(50, Color.Lime)); g.FillRectangle(bru, boundsPreview); } - - + } + + void DrawHidden(Graphics g) + { + if (_hiddenCount == 0) + return; + + var bounds = GetBounds(_itemsPtr.Count); + + var brush = new SolidBrush(Color.Black); + + g.DrawString($"{_hiddenCount} items hidden...", Font, brush, bounds); } } diff --git a/GUI/ContentManager.Designer.cs b/GUI/ContentManager.Designer.cs index b929ff1..4d8c5ba 100644 --- a/GUI/ContentManager.Designer.cs +++ b/GUI/ContentManager.Designer.cs @@ -29,45 +29,78 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { tableLayoutPanel1 = new TableLayoutPanel(); - AssetListBoxAvailable = new AssetViewBox(); AssetListBoxSelected = new AssetViewBox(); + textBoxSelectedFilter = new TextBox(); + textBoxAvailableFilter = new TextBox(); + AssetListBoxAvailable = new AssetViewBox(); tableLayoutPanel1.SuspendLayout(); SuspendLayout(); // // tableLayoutPanel1 // - tableLayoutPanel1.ColumnCount = 3; + tableLayoutPanel1.ColumnCount = 2; tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); - tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); - tableLayoutPanel1.Controls.Add(AssetListBoxAvailable, 2, 0); - tableLayoutPanel1.Controls.Add(AssetListBoxSelected, 0, 0); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); + tableLayoutPanel1.Controls.Add(AssetListBoxSelected, 0, 1); + tableLayoutPanel1.Controls.Add(textBoxSelectedFilter, 0, 0); + tableLayoutPanel1.Controls.Add(textBoxAvailableFilter, 1, 0); + tableLayoutPanel1.Controls.Add(AssetListBoxAvailable, 1, 1); tableLayoutPanel1.Dock = DockStyle.Fill; tableLayoutPanel1.Location = new Point(0, 0); tableLayoutPanel1.Name = "tableLayoutPanel1"; - tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowCount = 2; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); tableLayoutPanel1.Size = new Size(1204, 701); tableLayoutPanel1.TabIndex = 0; // - // AssetListBoxAvailable - // - AssetListBoxAvailable.Dock = DockStyle.Fill; - AssetListBoxAvailable.Location = new Point(612, 0); - AssetListBoxAvailable.Margin = new Padding(0); - AssetListBoxAvailable.Name = "AssetListBoxAvailable"; - AssetListBoxAvailable.Size = new Size(592, 701); - AssetListBoxAvailable.TabIndex = 0; - // // AssetListBoxSelected // + AssetListBoxSelected.BackColor = SystemColors.Window; AssetListBoxSelected.Dock = DockStyle.Fill; - AssetListBoxSelected.Location = new Point(0, 0); + AssetListBoxSelected.Filter = null; + AssetListBoxSelected.ItemHeight = 128; + AssetListBoxSelected.Location = new Point(0, 29); AssetListBoxSelected.Margin = new Padding(0); AssetListBoxSelected.Name = "AssetListBoxSelected"; - AssetListBoxSelected.Size = new Size(592, 701); + AssetListBoxSelected.OnItemClick = null; + AssetListBoxSelected.Position = 0; + AssetListBoxSelected.Size = new Size(602, 672); AssetListBoxSelected.TabIndex = 1; // + // textBoxSelectedFilter + // + textBoxSelectedFilter.Dock = DockStyle.Fill; + textBoxSelectedFilter.Location = new Point(3, 3); + textBoxSelectedFilter.Name = "textBoxSelectedFilter"; + textBoxSelectedFilter.Size = new Size(596, 23); + textBoxSelectedFilter.TabIndex = 2; + textBoxSelectedFilter.TextChanged += textBoxSelectedFilter_TextChanged; + // + // textBoxAvailableFilter + // + textBoxAvailableFilter.Dock = DockStyle.Fill; + textBoxAvailableFilter.Location = new Point(605, 3); + textBoxAvailableFilter.Name = "textBoxAvailableFilter"; + textBoxAvailableFilter.Size = new Size(596, 23); + textBoxAvailableFilter.TabIndex = 3; + textBoxAvailableFilter.TextChanged += textBoxAvailableFilter_TextChanged; + // + // AssetListBoxAvailable + // + AssetListBoxAvailable.BackColor = SystemColors.Window; + AssetListBoxAvailable.Dock = DockStyle.Fill; + AssetListBoxAvailable.Filter = null; + AssetListBoxAvailable.ItemHeight = 128; + AssetListBoxAvailable.Location = new Point(602, 29); + AssetListBoxAvailable.Margin = new Padding(0); + AssetListBoxAvailable.Name = "AssetListBoxAvailable"; + AssetListBoxAvailable.OnItemClick = null; + AssetListBoxAvailable.Position = 0; + AssetListBoxAvailable.Size = new Size(602, 672); + AssetListBoxAvailable.TabIndex = 0; + // // ContentManager // AutoScaleDimensions = new SizeF(7F, 15F); @@ -76,6 +109,7 @@ private void InitializeComponent() Name = "ContentManager"; Size = new Size(1204, 701); tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); ResumeLayout(false); } @@ -84,5 +118,7 @@ private void InitializeComponent() private TableLayoutPanel tableLayoutPanel1; public AssetViewBox AssetListBoxAvailable; public AssetViewBox AssetListBoxSelected; + private TextBox textBoxSelectedFilter; + private TextBox textBoxAvailableFilter; } } diff --git a/GUI/ContentManager.cs b/GUI/ContentManager.cs index dc2501c..21a964a 100644 --- a/GUI/ContentManager.cs +++ b/GUI/ContentManager.cs @@ -62,8 +62,8 @@ public void SetLibary(AssetLibary libary) ItemsChanged(); - TrySelcet(libary.TerrainMaterials, "10m_grid"); - TrySelcet(libary.LevelPresets, "Default"); + TrySelcet(libary.TerrainMaterials, "Core_10m_grid"); + TrySelcet(libary.LevelPresets, "Core_Default"); } void TrySelcet(AssetCollection values, string key) where T : Asset @@ -84,4 +84,14 @@ void ItemsChanged() AssetListBoxAvailable.ItemsChanged(); AssetListBoxSelected.ItemsChanged(); } + + private void textBoxSelectedFilter_TextChanged(object sender, EventArgs e) + { + AssetListBoxSelected.Filter = textBoxSelectedFilter.Text; + } + + private void textBoxAvailableFilter_TextChanged(object sender, EventArgs e) + { + AssetListBoxAvailable.Filter = textBoxAvailableFilter.Text; + } } diff --git a/GUI/ExceptionBox.cs b/GUI/ExceptionBox.cs new file mode 100644 index 0000000..c52670d --- /dev/null +++ b/GUI/ExceptionBox.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.GUI; + +internal static class ExceptionBox +{ + public static DialogResult Show(IWin32Window owner, Exception e) + { + return MessageBox.Show(owner, e.Message, e.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error); + } +} diff --git a/GUI/LabledTextbox.Designer.cs b/GUI/LabledTextbox.Designer.cs index 004cb94..70f0838 100644 --- a/GUI/LabledTextbox.Designer.cs +++ b/GUI/LabledTextbox.Designer.cs @@ -30,33 +30,54 @@ private void InitializeComponent() { TextBox = new TextBox(); Label = new Label(); + tableLayoutPanel1 = new TableLayoutPanel(); + tableLayoutPanel1.SuspendLayout(); SuspendLayout(); // // TextBox // TextBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - TextBox.Location = new Point(100, 0); + TextBox.Location = new Point(103, 3); TextBox.Name = "TextBox"; - TextBox.Size = new Size(260, 23); + TextBox.Size = new Size(354, 23); TextBox.TabIndex = 0; // // Label // + Label.Anchor = AnchorStyles.Left; Label.AutoSize = true; - Label.Location = new Point(3, 3); + Label.Location = new Point(3, 7); Label.Name = "Label"; Label.Size = new Size(32, 15); Label.TabIndex = 1; Label.Text = "label"; // + // tableLayoutPanel1 + // + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableLayoutPanel1.Controls.Add(Label, 0, 0); + tableLayoutPanel1.Controls.Add(TextBox, 1, 0); + tableLayoutPanel1.Dock = DockStyle.Top; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(460, 29); + tableLayoutPanel1.TabIndex = 2; + // // LabledTextbox // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - Controls.Add(Label); - Controls.Add(TextBox); + Controls.Add(tableLayoutPanel1); Name = "LabledTextbox"; - Size = new Size(360, 23); + Size = new Size(460, 29); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); ResumeLayout(false); PerformLayout(); } @@ -65,6 +86,6 @@ private void InitializeComponent() public TextBox TextBox; public Label Label; - private Label label1; + private TableLayoutPanel tableLayoutPanel1; } } diff --git a/GUI/LevelSettings.Designer.cs b/GUI/LevelSettings.Designer.cs index fd4642e..6dc1794 100644 --- a/GUI/LevelSettings.Designer.cs +++ b/GUI/LevelSettings.Designer.cs @@ -32,49 +32,65 @@ private void InitializeComponent() TextBoxNamespace = new LabledTextbox(); TextBoxTitle = new LabledTextbox(); TextBoxAuthor = new LabledTextbox(); + ButtonSave = new Button(); SuspendLayout(); // // TerainSettings // TerainSettings.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - TerainSettings.Location = new Point(3, 90); - TerainSettings.MaximumSize = new Size(10000, 116); + TerainSettings.Location = new Point(0, 87); + TerainSettings.Margin = new Padding(0); + TerainSettings.MaximumSize = new Size(10000, 145); TerainSettings.MinimumSize = new Size(0, 116); TerainSettings.Name = "TerainSettings"; - TerainSettings.Size = new Size(514, 116); + TerainSettings.Size = new Size(517, 145); TerainSettings.TabIndex = 0; // // TextBoxNamespace // TextBoxNamespace.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; TextBoxNamespace.LabelText = "Namespace"; - TextBoxNamespace.Location = new Point(3, 3); + TextBoxNamespace.Location = new Point(0, 0); + TextBoxNamespace.Margin = new Padding(0); TextBoxNamespace.Name = "TextBoxNamespace"; - TextBoxNamespace.Size = new Size(511, 23); + TextBoxNamespace.Size = new Size(517, 29); TextBoxNamespace.TabIndex = 1; // // TextBoxTitle // TextBoxTitle.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; TextBoxTitle.LabelText = "Title"; - TextBoxTitle.Location = new Point(3, 32); + TextBoxTitle.Location = new Point(0, 29); + TextBoxTitle.Margin = new Padding(0); TextBoxTitle.Name = "TextBoxTitle"; - TextBoxTitle.Size = new Size(511, 23); + TextBoxTitle.Size = new Size(517, 29); TextBoxTitle.TabIndex = 2; // // TextBoxAuthor // TextBoxAuthor.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; TextBoxAuthor.LabelText = "Authors"; - TextBoxAuthor.Location = new Point(3, 61); + TextBoxAuthor.Location = new Point(0, 58); + TextBoxAuthor.Margin = new Padding(0); TextBoxAuthor.Name = "TextBoxAuthor"; - TextBoxAuthor.Size = new Size(511, 23); + TextBoxAuthor.Size = new Size(517, 29); TextBoxAuthor.TabIndex = 3; // + // ButtonSave + // + ButtonSave.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + ButtonSave.Location = new Point(3, 509); + ButtonSave.Name = "ButtonSave"; + ButtonSave.Size = new Size(511, 23); + ButtonSave.TabIndex = 4; + ButtonSave.Text = "Save Level"; + ButtonSave.UseVisualStyleBackColor = true; + // // LevelSettings // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; + Controls.Add(ButtonSave); Controls.Add(TextBoxAuthor); Controls.Add(TextBoxTitle); Controls.Add(TextBoxNamespace); @@ -89,5 +105,6 @@ private void InitializeComponent() private LabledTextbox TextBoxNamespace; private LabledTextbox TextBoxTitle; private LabledTextbox TextBoxAuthor; + public Button ButtonSave; } } diff --git a/GUI/LevelSettings.cs b/GUI/LevelSettings.cs index 991dec9..6917fb5 100644 --- a/GUI/LevelSettings.cs +++ b/GUI/LevelSettings.cs @@ -28,16 +28,18 @@ public void SetLevel(Level level) TextBoxNamespace.Text = _level.Namespace; TextBoxTitle.Text = _level.Info.Title; TextBoxAuthor.Text = _level.Info.Authors; + + TextBoxNamespace.TextBox.TextChanged += Namespace_TextChanged; + TextBoxTitle.TextBox.TextChanged += Title_TextChanged; + TextBoxAuthor.TextBox.TextChanged += Authors_TextChanged; } public LevelSettings() { InitializeComponent(); - - } - private void textBoxNamespace_TextChanged(object sender, EventArgs e) + private void Namespace_TextChanged(object? sender, EventArgs e) { if (_level == null) return; @@ -45,7 +47,7 @@ private void textBoxNamespace_TextChanged(object sender, EventArgs e) _level.Namespace = TextBoxNamespace.Text; } - private void textBoxTitle_TextChanged(object sender, EventArgs e) + private void Title_TextChanged(object? sender, EventArgs e) { if (_level == null) return; @@ -53,7 +55,7 @@ private void textBoxTitle_TextChanged(object sender, EventArgs e) _level.Info.Title = TextBoxTitle.Text; } - private void textBoxAuthors_TextChanged(object sender, EventArgs e) + private void Authors_TextChanged(object? sender, EventArgs e) { if (_level == null) return; diff --git a/GUI/MainForm.Designer.cs b/GUI/MainForm.Designer.cs index 45f0c35..1e3c365 100644 --- a/GUI/MainForm.Designer.cs +++ b/GUI/MainForm.Designer.cs @@ -36,13 +36,14 @@ private void InitializeComponent() exitToolStripMenuItem = new ToolStripMenuItem(); settingsToolStripMenuItem = new ToolStripMenuItem(); systemToolStripMenuItem = new ToolStripMenuItem(); - utilsToolStripMenuItem = new ToolStripMenuItem(); - createTexturePackFromLevelToolStripMenuItem = new ToolStripMenuItem(); + reloadToolStripMenuItem = new ToolStripMenuItem(); displayToolStripMenuItem = new ToolStripMenuItem(); itemSizeToolStripMenuItem = new ToolStripMenuItem(); toolStripMenuItem2 = new ToolStripMenuItem(); toolStripMenuItem3 = new ToolStripMenuItem(); toolStripMenuItem4 = new ToolStripMenuItem(); + utilsToolStripMenuItem = new ToolStripMenuItem(); + createTexturePackFromLevelToolStripMenuItem = new ToolStripMenuItem(); splitContainer1 = new SplitContainer(); LevelSettings = new GUI.LevelSettings(); ContentManager = new GUI.ContentManager(); @@ -100,10 +101,10 @@ private void InitializeComponent() // // settingsToolStripMenuItem // - settingsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { systemToolStripMenuItem }); + settingsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { systemToolStripMenuItem, reloadToolStripMenuItem }); settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; - settingsToolStripMenuItem.Size = new Size(61, 20); - settingsToolStripMenuItem.Text = "Settings"; + settingsToolStripMenuItem.Size = new Size(62, 20); + settingsToolStripMenuItem.Text = "Content"; // // systemToolStripMenuItem // @@ -112,20 +113,12 @@ private void InitializeComponent() systemToolStripMenuItem.Text = "System Paths"; systemToolStripMenuItem.Click += systemToolStripMenuItem_Click; // - // utilsToolStripMenuItem - // - utilsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { createTexturePackFromLevelToolStripMenuItem }); - utilsToolStripMenuItem.Enabled = false; - utilsToolStripMenuItem.Name = "utilsToolStripMenuItem"; - utilsToolStripMenuItem.Size = new Size(42, 20); - utilsToolStripMenuItem.Text = "Utils"; - // - // createTexturePackFromLevelToolStripMenuItem + // reloadToolStripMenuItem // - createTexturePackFromLevelToolStripMenuItem.Name = "createTexturePackFromLevelToolStripMenuItem"; - createTexturePackFromLevelToolStripMenuItem.Size = new Size(238, 22); - createTexturePackFromLevelToolStripMenuItem.Text = "Create Texture Pack From Level"; - createTexturePackFromLevelToolStripMenuItem.Click += createTexturePackFromLevelToolStripMenuItem_Click; + reloadToolStripMenuItem.Name = "reloadToolStripMenuItem"; + reloadToolStripMenuItem.Size = new Size(180, 22); + reloadToolStripMenuItem.Text = "Reload"; + reloadToolStripMenuItem.Click += reloadToolStripMenuItem_Click; // // displayToolStripMenuItem // @@ -144,24 +137,39 @@ private void InitializeComponent() // toolStripMenuItem2 // toolStripMenuItem2.Name = "toolStripMenuItem2"; - toolStripMenuItem2.Size = new Size(180, 22); + toolStripMenuItem2.Size = new Size(150, 22); toolStripMenuItem2.Text = "Small Icons"; toolStripMenuItem2.Click += toolStripMenuItem2_Click; // // toolStripMenuItem3 // toolStripMenuItem3.Name = "toolStripMenuItem3"; - toolStripMenuItem3.Size = new Size(180, 22); + toolStripMenuItem3.Size = new Size(150, 22); toolStripMenuItem3.Text = "Medium Icons"; toolStripMenuItem3.Click += toolStripMenuItem3_Click; // // toolStripMenuItem4 // toolStripMenuItem4.Name = "toolStripMenuItem4"; - toolStripMenuItem4.Size = new Size(180, 22); + toolStripMenuItem4.Size = new Size(150, 22); toolStripMenuItem4.Text = "Large Icons"; toolStripMenuItem4.Click += toolStripMenuItem4_Click; // + // utilsToolStripMenuItem + // + utilsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { createTexturePackFromLevelToolStripMenuItem }); + utilsToolStripMenuItem.Enabled = false; + utilsToolStripMenuItem.Name = "utilsToolStripMenuItem"; + utilsToolStripMenuItem.Size = new Size(42, 20); + utilsToolStripMenuItem.Text = "Utils"; + // + // createTexturePackFromLevelToolStripMenuItem + // + createTexturePackFromLevelToolStripMenuItem.Name = "createTexturePackFromLevelToolStripMenuItem"; + createTexturePackFromLevelToolStripMenuItem.Size = new Size(238, 22); + createTexturePackFromLevelToolStripMenuItem.Text = "Create Texture Pack From Level"; + createTexturePackFromLevelToolStripMenuItem.Click += createTexturePackFromLevelToolStripMenuItem_Click; + // // splitContainer1 // splitContainer1.Dock = DockStyle.Fill; @@ -229,7 +237,6 @@ private void InitializeComponent() private ToolStripMenuItem systemToolStripMenuItem; private ToolStripMenuItem utilsToolStripMenuItem; private ToolStripMenuItem createTexturePackFromLevelToolStripMenuItem; - private Label label1; private SplitContainer splitContainer1; private GUI.LevelSettings LevelSettings; private GUI.ContentManager ContentManager; @@ -238,5 +245,6 @@ private void InitializeComponent() private ToolStripMenuItem toolStripMenuItem2; private ToolStripMenuItem toolStripMenuItem3; private ToolStripMenuItem toolStripMenuItem4; + private ToolStripMenuItem reloadToolStripMenuItem; } } diff --git a/GUI/MainForm.cs b/GUI/MainForm.cs index e61beaa..e1cec51 100644 --- a/GUI/MainForm.cs +++ b/GUI/MainForm.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Text; using LevelTemplateCreator.Assets; +using LevelTemplateCreator.GUI; namespace LevelTemplateCreator { @@ -14,7 +15,12 @@ public MainForm() InitializeComponent(); AssetLibary = new AssetLibary(); - Level = new Level(); + Level = new Level(AssetLibary); + + LevelSettings.ButtonSave.Click += (object? sender, EventArgs e) => + { + Export(); + }; } private void groupBox2_Enter(object sender, EventArgs e) @@ -93,14 +99,20 @@ void Export(string path) } } - Directory.CreateDirectory(fullPath); + try + { + Directory.CreateDirectory(fullPath); - Level.Content.Clear(); - Level.Content.Add(ContentManager.GetSelectedAssets()); - Level.Content.Preview = AssetLibary.Preview; - Level.Content.PrintSumary(); + Level.SetContent(ContentManager.GetSelectedAssets()); + Level.Export(fullPath); + } + catch (Exception e) + { + ExceptionBox.Show(this, e); - Level.Export(fullPath); + if (Program.Debug) + throw; + } if (MessageBox.Show(this, $"Level '{Level.Namespace}' at '{path}' successfully created, do you want to open it now?", "Template successfully created", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) @@ -119,27 +131,25 @@ private void exitToolStripMenuItem_Click(object sender, EventArgs e) private void MainForm_Load(object sender, EventArgs e) { - + LevelSettings.SetLevel(Level); EnvironmentInfo.Load(); - AssertEnvironmentInfo(); + LoadContent(); + } - if (!EnvironmentInfo.Packages.IsValid) - { - Close(); + void LoadContent() + { + if (!AssertEnvironmentInfo()) return; - } - EnvironmentInfo.PrintSumary(); + AssetLibary.Clear(); - var loader = new AssetLibaryLoader(AssetLibary); + var loader = new AssetLibaryLoader(AssetLibary) { Debug = Program.Debug }; loader.LoadDirectory(EnvironmentInfo.Packages.Path); loader.PrintErrors(); AssetLibary.SeperateGroundCoverInstances(); AssetLibary.PrintSumary(); - LevelSettings.SetLevel(Level); - ContentManager.SetLibary(AssetLibary); } @@ -157,5 +167,10 @@ private void toolStripMenuItem4_Click(object sender, EventArgs e) { ContentManager.SetItemHeight(256); } + + private void reloadToolStripMenuItem_Click(object sender, EventArgs e) + { + LoadContent(); + } } } diff --git a/GUI/TerrainSettings.Designer.cs b/GUI/TerrainSettings.Designer.cs index 558d550..09a7a6d 100644 --- a/GUI/TerrainSettings.Designer.cs +++ b/GUI/TerrainSettings.Designer.cs @@ -28,64 +28,67 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - numericUpDownWorldSize = new NumericUpDown(); + numericWorldSize = new NumericUpDown(); comboBoxRes = new ComboBox(); - numericUpDownSquareSize = new NumericUpDown(); - numericUpDownMaxHeight = new NumericUpDown(); + numericSquareSize = new NumericUpDown(); + numericMaxHeight = new NumericUpDown(); label1 = new Label(); label2 = new Label(); label3 = new Label(); label4 = new Label(); tableLayoutPanel1 = new TableLayoutPanel(); - ((System.ComponentModel.ISupportInitialize)numericUpDownWorldSize).BeginInit(); - ((System.ComponentModel.ISupportInitialize)numericUpDownSquareSize).BeginInit(); - ((System.ComponentModel.ISupportInitialize)numericUpDownMaxHeight).BeginInit(); + numericBaseHeight = new NumericUpDown(); + label5 = new Label(); + ((System.ComponentModel.ISupportInitialize)numericWorldSize).BeginInit(); + ((System.ComponentModel.ISupportInitialize)numericSquareSize).BeginInit(); + ((System.ComponentModel.ISupportInitialize)numericMaxHeight).BeginInit(); tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)numericBaseHeight).BeginInit(); SuspendLayout(); // - // numericUpDownWorldSize + // numericWorldSize // - numericUpDownWorldSize.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - numericUpDownWorldSize.DecimalPlaces = 2; - numericUpDownWorldSize.Location = new Point(100, 32); - numericUpDownWorldSize.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); - numericUpDownWorldSize.Name = "numericUpDownWorldSize"; - numericUpDownWorldSize.Size = new Size(308, 23); - numericUpDownWorldSize.TabIndex = 3; - numericUpDownWorldSize.ValueChanged += numericUpDownWorldSize_ValueChanged; + numericWorldSize.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + numericWorldSize.DecimalPlaces = 2; + numericWorldSize.Location = new Point(101, 32); + numericWorldSize.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); + numericWorldSize.Name = "numericWorldSize"; + numericWorldSize.Size = new Size(477, 23); + numericWorldSize.TabIndex = 3; + numericWorldSize.ValueChanged += numericUpDownWorldSize_ValueChanged; // // comboBoxRes // comboBoxRes.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; comboBoxRes.FormattingEnabled = true; comboBoxRes.Items.AddRange(new object[] { "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "65536" }); - comboBoxRes.Location = new Point(100, 3); + comboBoxRes.Location = new Point(101, 3); comboBoxRes.Name = "comboBoxRes"; - comboBoxRes.Size = new Size(308, 23); + comboBoxRes.Size = new Size(477, 23); comboBoxRes.TabIndex = 4; comboBoxRes.SelectedIndexChanged += comboBoxRes_SelectedIndexChanged; // - // numericUpDownSquareSize + // numericSquareSize // - numericUpDownSquareSize.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - numericUpDownSquareSize.DecimalPlaces = 2; - numericUpDownSquareSize.Location = new Point(100, 61); - numericUpDownSquareSize.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); - numericUpDownSquareSize.Name = "numericUpDownSquareSize"; - numericUpDownSquareSize.Size = new Size(308, 23); - numericUpDownSquareSize.TabIndex = 5; - numericUpDownSquareSize.ValueChanged += numericUpDownSquareSize_ValueChanged; + numericSquareSize.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + numericSquareSize.DecimalPlaces = 2; + numericSquareSize.Location = new Point(101, 61); + numericSquareSize.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); + numericSquareSize.Name = "numericSquareSize"; + numericSquareSize.Size = new Size(477, 23); + numericSquareSize.TabIndex = 5; + numericSquareSize.ValueChanged += numericUpDownSquareSize_ValueChanged; // - // numericUpDownMaxHeight + // numericMaxHeight // - numericUpDownMaxHeight.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - numericUpDownMaxHeight.DecimalPlaces = 2; - numericUpDownMaxHeight.Location = new Point(100, 90); - numericUpDownMaxHeight.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); - numericUpDownMaxHeight.Name = "numericUpDownMaxHeight"; - numericUpDownMaxHeight.Size = new Size(308, 23); - numericUpDownMaxHeight.TabIndex = 6; - numericUpDownMaxHeight.ValueChanged += numericUpDownMaxHeight_ValueChanged; + numericMaxHeight.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + numericMaxHeight.DecimalPlaces = 2; + numericMaxHeight.Location = new Point(101, 90); + numericMaxHeight.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); + numericMaxHeight.Name = "numericMaxHeight"; + numericMaxHeight.Size = new Size(477, 23); + numericMaxHeight.TabIndex = 6; + numericMaxHeight.ValueChanged += numericUpDownMaxHeight_ValueChanged; // // label1 // @@ -134,52 +137,79 @@ private void InitializeComponent() tableLayoutPanel1.ColumnCount = 2; tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); - tableLayoutPanel1.Controls.Add(numericUpDownMaxHeight, 1, 3); + tableLayoutPanel1.Controls.Add(numericBaseHeight, 1, 4); + tableLayoutPanel1.Controls.Add(numericMaxHeight, 1, 3); tableLayoutPanel1.Controls.Add(label4, 0, 3); - tableLayoutPanel1.Controls.Add(numericUpDownSquareSize, 1, 2); + tableLayoutPanel1.Controls.Add(numericSquareSize, 1, 2); tableLayoutPanel1.Controls.Add(label2, 0, 1); - tableLayoutPanel1.Controls.Add(numericUpDownWorldSize, 1, 1); + tableLayoutPanel1.Controls.Add(numericWorldSize, 1, 1); tableLayoutPanel1.Controls.Add(comboBoxRes, 1, 0); tableLayoutPanel1.Controls.Add(label3, 0, 2); tableLayoutPanel1.Controls.Add(label1, 0, 0); + tableLayoutPanel1.Controls.Add(label5, 0, 4); tableLayoutPanel1.Dock = DockStyle.Top; tableLayoutPanel1.Location = new Point(0, 0); tableLayoutPanel1.Name = "tableLayoutPanel1"; - tableLayoutPanel1.RowCount = 4; + tableLayoutPanel1.RowCount = 5; tableLayoutPanel1.RowStyles.Add(new RowStyle()); tableLayoutPanel1.RowStyles.Add(new RowStyle()); tableLayoutPanel1.RowStyles.Add(new RowStyle()); tableLayoutPanel1.RowStyles.Add(new RowStyle()); - tableLayoutPanel1.Size = new Size(411, 116); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.Size = new Size(581, 145); tableLayoutPanel1.TabIndex = 11; // + // numericBaseHeight + // + numericBaseHeight.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + numericBaseHeight.DecimalPlaces = 2; + numericBaseHeight.Location = new Point(101, 119); + numericBaseHeight.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); + numericBaseHeight.Name = "numericBaseHeight"; + numericBaseHeight.Size = new Size(477, 23); + numericBaseHeight.TabIndex = 12; + numericBaseHeight.ValueChanged += numericBaseHeight_ValueChanged; + // + // label5 + // + label5.Anchor = AnchorStyles.Left; + label5.AutoSize = true; + label5.Location = new Point(3, 123); + label5.Name = "label5"; + label5.Size = new Size(92, 15); + label5.TabIndex = 13; + label5.Text = "Base Height (m)"; + // // TerrainSettings // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; Controls.Add(tableLayoutPanel1); - MaximumSize = new Size(10000, 116); - MinimumSize = new Size(0, 116); + MaximumSize = new Size(10000, 145); + MinimumSize = new Size(0, 145); Name = "TerrainSettings"; - Size = new Size(411, 116); - ((System.ComponentModel.ISupportInitialize)numericUpDownWorldSize).EndInit(); - ((System.ComponentModel.ISupportInitialize)numericUpDownSquareSize).EndInit(); - ((System.ComponentModel.ISupportInitialize)numericUpDownMaxHeight).EndInit(); + Size = new Size(581, 145); + ((System.ComponentModel.ISupportInitialize)numericWorldSize).EndInit(); + ((System.ComponentModel.ISupportInitialize)numericSquareSize).EndInit(); + ((System.ComponentModel.ISupportInitialize)numericMaxHeight).EndInit(); tableLayoutPanel1.ResumeLayout(false); tableLayoutPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)numericBaseHeight).EndInit(); ResumeLayout(false); PerformLayout(); } #endregion - private NumericUpDown numericUpDownWorldSize; + private NumericUpDown numericWorldSize; private ComboBox comboBoxRes; - private NumericUpDown numericUpDownSquareSize; - private NumericUpDown numericUpDownMaxHeight; + private NumericUpDown numericSquareSize; + private NumericUpDown numericMaxHeight; private Label label1; private Label label2; private Label label3; private Label label4; private TableLayoutPanel tableLayoutPanel1; + private NumericUpDown numericBaseHeight; + private Label label5; } } diff --git a/GUI/TerrainSettings.cs b/GUI/TerrainSettings.cs index 7858f8c..c54fd7b 100644 --- a/GUI/TerrainSettings.cs +++ b/GUI/TerrainSettings.cs @@ -23,7 +23,9 @@ internal TerrainInfo Terrain { _terrain = value; comboBoxRes.SelectedText = _terrain.Resolution.ToString(); - numericUpDownMaxHeight.Value = _terrain.MaxHeight; + numericMaxHeight.Value = (decimal)_terrain.MaxHeight; + numericBaseHeight.Value = (decimal)_terrain.Height; + UpdatenumericBaseHeightColor(); UpdateDisplay(); } @@ -33,9 +35,11 @@ public TerrainSettings() { InitializeComponent(); - numericUpDownWorldSize.Maximum = decimal.MaxValue; - numericUpDownSquareSize.Maximum = decimal.MaxValue; - numericUpDownMaxHeight.Maximum = decimal.MaxValue; + _terrain = null!; + + numericWorldSize.Maximum = decimal.MaxValue; + numericSquareSize.Maximum = decimal.MaxValue; + numericMaxHeight.Maximum = decimal.MaxValue; } @@ -44,8 +48,8 @@ public void UpdateDisplay() { isUpdating = true; - numericUpDownWorldSize.Value = (decimal)Terrain.WorldSize; - numericUpDownSquareSize.Value = (decimal)Terrain.SquareSize; + numericWorldSize.Value = (decimal)Terrain.WorldSize; + numericSquareSize.Value = (decimal)Terrain.SquareSize; isUpdating = false; } @@ -58,7 +62,8 @@ private void comboBoxRes_SelectedIndexChanged(object sender, EventArgs e) var text = comboBoxRes.Text; Terrain.Resolution = int.Parse(text); - if (comboBoxRes.SelectedIndex == -1) { + if (comboBoxRes.SelectedIndex == -1) + { comboBoxRes.ForeColor = Color.Red; } else @@ -74,7 +79,7 @@ private void numericUpDownWorldSize_ValueChanged(object sender, EventArgs e) if (isUpdating) return; - Terrain.WorldSize = (float)numericUpDownWorldSize.Value; + Terrain.WorldSize = (float)numericWorldSize.Value; UpdateDisplay(); } @@ -84,16 +89,25 @@ private void numericUpDownSquareSize_ValueChanged(object sender, EventArgs e) if (isUpdating) return; - Terrain.SquareSize = (float)numericUpDownSquareSize.Value; + Terrain.SquareSize = (float)numericSquareSize.Value; UpdateDisplay(); } private void numericUpDownMaxHeight_ValueChanged(object sender, EventArgs e) { - if (isUpdating) - return; + Terrain.MaxHeight = (float)numericMaxHeight.Value; + UpdatenumericBaseHeightColor(); + } - Terrain.MaxHeight = (int)numericUpDownMaxHeight.Value; + private void numericBaseHeight_ValueChanged(object sender, EventArgs e) + { + Terrain.Height = (float)numericBaseHeight.Value; + UpdatenumericBaseHeightColor(); + } + + void UpdatenumericBaseHeightColor() + { + numericBaseHeight.ForeColor = Terrain.Height > Terrain.MaxHeight ? Color.Red : Color.Black; } } diff --git a/IO/Resources/Resource.cs b/IO/Resources/Resource.cs index 94cdc20..396bd6e 100644 --- a/IO/Resources/Resource.cs +++ b/IO/Resources/Resource.cs @@ -1,4 +1,5 @@ -using LevelTemplateCreator.Properties; +using LevelTemplateCreator.Collections; +using LevelTemplateCreator.Properties; using System; using System.Collections.Generic; using System.IO; @@ -8,8 +9,10 @@ namespace LevelTemplateCreator.IO.Resources; -internal abstract class Resource +internal abstract class Resource : IKeyed { + string IKeyed.Key => Name; + public string Name { get; } public string DynamicName { get; protected set; } diff --git a/IO/Resources/ResourceCollection.cs b/IO/Resources/ResourceCollection.cs new file mode 100644 index 0000000..f6f035c --- /dev/null +++ b/IO/Resources/ResourceCollection.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Globalization; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LevelTemplateCreator.SceneTree.Art; +using LevelTemplateCreator.Collections; + +namespace LevelTemplateCreator.IO.Resources; + +internal class ResourceCollection : KeyedCollection +{ + public string Register(string entry) + { + var resource = ResourceManager.Parse(entry); + var key = resource.Name; + if (ContainsKey(key)) + return key; + Add(resource); + return key; + } + + public string RegisterRelative(string entry, string rootPath) + { + var resource = ResourceManager.ParseRelative(entry, rootPath); + var key = resource.Name; + if (ContainsKey(key)) + return key; + Add(resource); + return key; + } + + public void Save(string path) + { + foreach (var resource in this) + { + resource.SaveToDirectory(path); + } + } +} diff --git a/IO/Resources/ResourceManager.cs b/IO/Resources/ResourceManager.cs index e351a19..e46bf6f 100644 --- a/IO/Resources/ResourceManager.cs +++ b/IO/Resources/ResourceManager.cs @@ -1,66 +1,20 @@ using System; -using System.Collections; -using System.Globalization; using System.Collections.Generic; -using System.IO.Compression; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; -using LevelTemplateCreator.SceneTree.Art; namespace LevelTemplateCreator.IO.Resources; -internal class ResourceManager : IEnumerable +internal static class ResourceManager { - public Dictionary Files { get; } - - - static readonly Dictionary _colors; - - static ResourceManager() - { - _colors = new(); - } - - public ResourceManager() - { - Files = new Dictionary(); - } - - public Resource Get(string key) - { - return Files[key]; - } - - public Resource this[string key] => Get(key); - - public void Add(Resource ressource) - { - if (Files.ContainsKey(ressource.Name)) - return; - Files[ressource.Name] = ressource; - } - - public string Register(string entry) - { - var resource = Parse(entry); - Add(resource); - return resource.Name; - } - - public string Register(string entry, string file) - { - var resource = Parse(entry, file); - Add(resource); - return resource.Name; - } - - public static Resource Parse(string entry, string file) + public static Resource ParseRelative(string entry, string rootPath) { if (entry.StartsWith('.')) { var abspackpath = Path.GetFullPath(EnvironmentInfo.Packages.Path); - var dirpath = Path.GetDirectoryName(file); + var dirpath = Path.GetDirectoryName(rootPath); if (dirpath == null) throw new Exception(); var path = Path.GetFullPath(Path.Combine(dirpath, entry)); @@ -120,22 +74,4 @@ public static Resource Parse(string entry) throw new Exception(); } - - public void Save(string path) - { - foreach (var resource in Files.Values) - { - resource.SaveToDirectory(path); - } - } - - public IEnumerator GetEnumerator() - { - return Files.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return Files.Values.GetEnumerator(); - } } diff --git a/IO/Resources/SolidColorNames.cs b/IO/Resources/SolidColorNames.cs index af963ac..2074328 100644 --- a/IO/Resources/SolidColorNames.cs +++ b/IO/Resources/SolidColorNames.cs @@ -17,10 +17,12 @@ internal static class SolidColorNames public const string BaseColor = "#base_b"; public const string BaseRoughness = "#base_r"; + public const string ConcreteRoughness = "#concrete_r"; public const string AsphaltRoughness = "#asphalt_r"; public const string AsphaltWetRoughness = "#asphalt_wet_r"; public const string GrassRoughness = "#grass_r"; + public const string SandRoughness = "#sand_r"; public const string DirtRoughness = "#dirt_r"; public const string RockRoughness = "#rock_r"; public const string MudRoughness = "#mud_r"; @@ -34,9 +36,11 @@ static SolidColorNames() _colors[BaseRoughness] = 0xe7e7e7; _colors[BaseColor] = 0x808080; + _colors[ConcreteRoughness] = 0xd4d4d4; _colors[AsphaltRoughness] = 0xd4d4d4; _colors[AsphaltWetRoughness] = 0x464646; _colors[GrassRoughness] = 0xe7e7e7; + _colors[SandRoughness] = 0xe7e7e7; _colors[DirtRoughness] = 0xe7e7e7; _colors[RockRoughness] = 0xd4d4d4; _colors[MudRoughness] = 0x464646; diff --git a/IO/TerrainV9Serializer.cs b/IO/TerrainV9Serializer.cs index 8856b27..18c7efb 100644 --- a/IO/TerrainV9Serializer.cs +++ b/IO/TerrainV9Serializer.cs @@ -10,13 +10,13 @@ namespace LevelTemplateCreator.IO; static class TerrainV9Serializer { - public static void Serialize(TerrainInfo info, string[] materials, string path) + public static void Serialize(TerrainInfo info, ICollection materials, string path) { using var stream = new FileStream(path, FileMode.Create); Serialize(info, materials, stream); } - public static void Serialize(TerrainInfo info, string[] materials, Stream stream) + public static void Serialize(TerrainInfo info, ICollection materials, Stream stream) { using var bw = new BinaryViewWriter(stream); @@ -25,9 +25,22 @@ public static void Serialize(TerrainInfo info, string[] materials, Stream stream long size = info.Resolution * (long)info.Resolution; - bw.Seek(size * 3L, SeekOrigin.Current); + float u16max = ushort.MaxValue; - bw.WriteUInt32((uint)materials.Length); + float height = info.Height / info.MaxHeight * u16max; + if (height > u16max) + height = u16max; + + ushort u16height = (ushort)height; + + for (int i = 0; i < size; i++) + { + bw.WriteUInt16(u16height); + } + + bw.Seek(size, SeekOrigin.Current); + + bw.WriteUInt32((uint)materials.Count); foreach (var material in materials) { diff --git a/Level.cs b/Level.cs index ad4b321..9b4725d 100644 --- a/Level.cs +++ b/Level.cs @@ -11,12 +11,15 @@ using LevelTemplateCreator.SceneTree.Main; using LevelTemplateCreator.IO.Resources; using LevelTemplateCreator.Properties; +using LevelTemplateCreator.GUI; namespace LevelTemplateCreator; internal class Level { - public AssetLibary Content { get; } + public AssetLibary Libary { get; } + + public AssetLibaryContent Content { get; } public string Namespace { get; set; } @@ -24,7 +27,7 @@ internal class Level public TerrainInfo Terrain { get; set; } - public Level() + public Level(AssetLibary libary) { Namespace = "new_pbr_template"; Info = new LevelInfo(); @@ -32,7 +35,8 @@ public Level() { Resolution = 1024, }; - Content = new AssetLibary(); + Content = new AssetLibaryContent(); + Libary = libary; } public TerrainBlock BuildTerrainBlock() @@ -43,10 +47,10 @@ public TerrainBlock BuildTerrainBlock() return terrain; } - public MaterialLibary BuildTerrainMaterialLibary() + public TerrainMaterialLibary BuildTerrainMaterialLibary() { var path = $"/levels/{Namespace}/art/terrains"; - var lib = new MaterialLibary(path); + var lib = new TerrainMaterialLibary(path, Terrain.SquareSize); lib.AddAssets(Content.TerrainMaterials); lib.CreateTerrainMaterialTextureSet($"{Namespace}_TerrainMaterialTextureSet"); @@ -60,6 +64,9 @@ public SimGroup BuildMissionGroup() var group = root.MissionGroup; var levelObject = group.LevelObject; + var spawn = new SpawnSphere(Terrain.Height); + group.PlayerDropPoints.Items.Add(spawn); + var terrain = BuildTerrainBlock(); levelObject.Terrain.Items.Add(terrain); @@ -68,14 +75,25 @@ public SimGroup BuildMissionGroup() preset.Apply(levelObject); } - foreach (var cover in Content.GroundCoverDefinitions) + foreach (var cover in Content.GroundCoverObjects) { - levelObject.Vegatation.Items.Add(cover.GroundCover); + levelObject.Vegatation.Items.Add(cover); } return root; } + public void SetContent(Asset[] assets) + { + Content.Clear(); + Content.Add(assets); + Content.Preview = Libary.Preview; + Content.GetAssets(Libary); + Content.PrintSumary(); + } + + + public void Export(string path) { Directory.CreateDirectory(Path.Combine(path, "art/terrains")); @@ -83,7 +101,7 @@ public void Export(string path) Directory.CreateDirectory(Path.Combine(path, "art/objects")); var objpath = $"/levels/{Namespace}/art/objects"; - var lib = new MaterialLibary(objpath); + var lib = new ObjectMaterialLibary(objpath); lib.AddAssets(Content.ObjectMaterials); lib.SerializeItems(Path.Combine(path, "art/objects/" + MaterialLibary.FileName)); @@ -103,12 +121,11 @@ public void Export(string path) BuildMissionGroup().SaveTree(Path.Combine(path, "main")); - var names = terrainMaterials.GetMaterialNames(); - - TerrainV9Serializer.Serialize(Terrain, names, Path.Combine(path, "terrain.ter")); + TerrainV9Serializer.Serialize(Terrain, Content.TerrainMaterials.Keys, Path.Combine(path, "terrain.ter")); LevelInfoSerializer.Serialize(this, Path.Combine(path, "info.json")); ZipFileManager.Clear(); + Console.WriteLine(); } } diff --git a/LevelInfo.cs b/LevelInfo.cs index 1c3cdcc..1e9cc55 100644 --- a/LevelInfo.cs +++ b/LevelInfo.cs @@ -19,10 +19,10 @@ public LevelInfo() { Title = "New Level"; Description = string.Empty; - Authors = string.Empty; + Authors = Environment.UserName; } - public void Serialize(Dictionary dict) + public void Serialize(JsonDict dict) { dict["title"] = Title; dict["description"] = Description; diff --git a/LevelTemplateCreator.sln b/LevelTemplateCreator.sln index 6414c34..0fc15f2 100644 --- a/LevelTemplateCreator.sln +++ b/LevelTemplateCreator.sln @@ -3,7 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34525.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelTemplateCreator", "LevelTemplateCreator.csproj", "{C31B145C-37AF-46FA-B194-BB982020A461}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelTemplateCreator", "LevelTemplateCreator.csproj", "{C31B145C-37AF-46FA-B194-BB982020A461}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C3C03C73-5671-4D98-A299-32AC586BBA17}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Program.cs b/Program.cs index 278a8e3..8ce91c2 100644 --- a/Program.cs +++ b/Program.cs @@ -1,27 +1,24 @@ -using LevelTemplateCreator.SceneTree; -using System.IO.Compression; -using System.Text.Json; -using System.Text.Json.Serialization; +using System.Globalization; -namespace LevelTemplateCreator -{ - internal static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - // To customize application configuration such as set high DPI settings or default font, - // see https://aka.ms/applicationconfiguration. - ApplicationConfiguration.Initialize(); - Application.Run(new MainForm()); +namespace LevelTemplateCreator; +internal static class Program +{ - //var zip = ZipFile.Open("",ZipArchiveMode.Read); +#if DEBUG + public const bool Debug = true; +#else + public const bool Debug = false; +#endif - //var entry = zip.GetEntry("fg"); - } + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); } } \ No newline at end of file diff --git a/Properties/PublishProfiles/FolderProfile.pubxml b/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..9789242 --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + bin\Release\net6.0-windows\publish\win-x64\ + FileSystem + <_TargetId>Folder + net6.0-windows + false + win-x64 + true + false + + \ No newline at end of file diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..6002a0c --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,10 @@ + + + + + True|2024-05-08T00:44:53.8360334Z;True|2024-05-08T02:03:16.1586368+02:00;True|2024-05-08T02:01:32.0423000+02:00;True|2024-05-08T02:00:48.2796121+02:00; + + + \ No newline at end of file diff --git a/README.md b/README.md index 8c6fb60..30575a4 100644 --- a/README.md +++ b/README.md @@ -5,33 +5,56 @@ The goal of this project is to provide an easy solution to create empty map temp I also aimed to make it easily extendable for people with deeper knowledge of BeamNG. ## Features -• Setup of needed level folder structure without manual renaming. -• Asset System based on beaming’s Json structure. -• Ability to reference built-in BeamNG content, on export the referenced files are extracted to the template level. +* Setup of needed level folder structure without manual renaming. +* Asset System based on BeamNG's Json structure. +* Ability to reference built-in BeamNG content, on export the referenced files are extracted to the template level. + +## Future +* I would like to add support for Tree Objects, currently they still must be copied over manually. + +## Usage +Just click the assets on the rights side, and press save when you're happy. + +## Paths +* Gamedata: +Path to the BeamNG installation files, the folder should contain the BeamNG.drive.exe file. + +* Userdata: +BeamNG user data folder that contains settings and mods, path should point to the folder containing the version.txt +Can usually be found under User\AppData\Local\BeamNG.drive + ## Assets +If you want to create custom template assets, you’re can mostly use the same file structure as in BeamNG. +But there a few things to be noted: all names are prefixed with the folder they are in to prevent conflicts. +So, if your want assets to reference each other they should generally be in the same folder. ### Asset Types - `LevelPreset` -Contains a collection of items that are sorted into `Level_object` on export, preset can by selected in the GUI. +* `LevelObjects` +Contains a collection of generic items that are sorted into `Level_object` on export. -`TerrainMaterial` -BeamNG PBR Terrain Material, multiple can be chosen by user. +* `TerrainMaterial` +BeamNG PBR Terrain Material. -`GroundCover` +* `GroundCover` Ground Cover like grass, indirectly added if used by `TerrainMaterial` -`Material` +* `Material` Object material, indirectly added if used by any other object. ### Paths -`.` +* `.` Relative path from the folder containing the Json file. -`/` +* `/` Absolute path either from the local package folder, or alternatively if beginning with `/level` and contains an valid BeamNG-level name e.g `/levels/driver_training/` an pointer to an BeamNG resource. -`#` +* `#` Hex color code `#ffffff` used to generate a single-color texture file on export. + +Each part must start with one of the above characters. + +## Requirements +This program is dependent on .NET6 x64 \ No newline at end of file diff --git a/SceneTree/Art/ForestItemData.cs b/SceneTree/Art/ForestItemData.cs new file mode 100644 index 0000000..d250ade --- /dev/null +++ b/SceneTree/Art/ForestItemData.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.SceneTree.Art; + +internal class ForestItemData : JsonDictWrapper +{ + public const string ClassName = "TSForestItemData"; + + public JsonDictProperty ShapeFile { get; } + + public ForestItemData(JsonDict dict) : base(dict) + { + ShapeFile = new(this, "shapeFile"); + } +} diff --git a/SceneTree/Art/Material.cs b/SceneTree/Art/Material.cs index 0a2bddc..153b0fd 100644 --- a/SceneTree/Art/Material.cs +++ b/SceneTree/Art/Material.cs @@ -17,5 +17,5 @@ protected Material(JsonDict dict) : base(dict) public abstract void ResolveTexturePaths(MaterialLibary libary, string path); - public abstract Material Copy(); + public override abstract Material Copy(); } diff --git a/SceneTree/Art/MaterialLibary.cs b/SceneTree/Art/MaterialLibary.cs index bb0dcce..4d8f82a 100644 --- a/SceneTree/Art/MaterialLibary.cs +++ b/SceneTree/Art/MaterialLibary.cs @@ -13,33 +13,38 @@ namespace LevelTemplateCreator.SceneTree.Art; -internal class MaterialLibary +internal abstract class MaterialLibary { - public string TexturesPath { get; } + public const string FileName = "main.materials.json"; - public ResourceManager Textures { get; } + public string TexturesPath { get; } - public List Materials { get; } + public ResourceCollection Textures { get; } public List Misc { get; } + public abstract IEnumerable Materials { get; } + public MaterialLibary(string path) { TexturesPath = path; - Materials = new(); Misc = new(); Textures = new(); } +} - public void AddAsset(MaterialAsset asset) - { - var material = asset.Material.Copy(); - material.ResolveTexturePaths(this, asset.SourceFile); +internal abstract class MaterialLibary : MaterialLibary where T : Material +{ + public override List Materials { get; } - Materials.Add(material); + public MaterialLibary(string path) : base(path) + { + Materials = new(); } - public void AddAssets(IEnumerable assets) + public abstract void AddAsset(TAsset asset) where TAsset : MaterialAsset; + + public void AddAssets(IEnumerable assets) where TAsset : MaterialAsset { foreach (var asset in assets) { @@ -53,16 +58,11 @@ public string[] GetMaterialNames() var result = new string[Materials.Count]; for (int i = 0; i < result.Length; i++) { - result[i] = Materials[i].InternalName.Value; + result[i] = Materials[i].Name.Value; } return result; } - public void CreateTerrainMaterialTextureSet(string name) - { - Misc.Add(new TerrainPbrMaterialTextureSet(name)); - } - public void SerializeItems(string path) { using var stream = new FileStream(path, FileMode.Create); @@ -85,6 +85,4 @@ public void SerializeItems(Stream stream) JsonDictSerializer.Serialize(stream, dict, true); } - - public const string FileName = "main.materials.json"; } diff --git a/SceneTree/Art/ObjectMaterial.cs b/SceneTree/Art/ObjectMaterial.cs index 40750db..dc7e9b8 100644 --- a/SceneTree/Art/ObjectMaterial.cs +++ b/SceneTree/Art/ObjectMaterial.cs @@ -43,13 +43,13 @@ public override void ResolveTexturePaths(MaterialLibary libary, string path) { if (!map.Exists) continue; - var key = libary.Textures.Register(map.Value, path); + var key = libary.Textures.RegisterRelative(map.Value, path); map.Value = Path.Combine(libary.TexturesPath, key); } } } - public override Material Copy() + public override ObjectMaterial Copy() { var clone = new JsonDict(Dict); var stages = new JsonDict[4] { new(Stage0.Dict), new(Stage1.Dict), new(Stage2.Dict), new(Stage3.Dict) }; diff --git a/SceneTree/Art/ObjectMaterialLibary.cs b/SceneTree/Art/ObjectMaterialLibary.cs new file mode 100644 index 0000000..33cc9c2 --- /dev/null +++ b/SceneTree/Art/ObjectMaterialLibary.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.SceneTree.Art; + +internal class ObjectMaterialLibary : MaterialLibary +{ + public ObjectMaterialLibary(string path) : base(path) + { + } + + public override void AddAsset(TAsset asset) + { + var copy = asset.GetCopy(); + copy.ResolveTexturePaths(this, asset.SourceFile); + Materials.Add(copy); + } +} diff --git a/SceneTree/Art/TerrainPbrMaterial.cs b/SceneTree/Art/TerrainMaterial.cs similarity index 71% rename from SceneTree/Art/TerrainPbrMaterial.cs rename to SceneTree/Art/TerrainMaterial.cs index 174bbca..cf01139 100644 --- a/SceneTree/Art/TerrainPbrMaterial.cs +++ b/SceneTree/Art/TerrainMaterial.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace LevelTemplateCreator.SceneTree.Art; -internal class TerrainPbrMaterial : Material +internal class TerrainMaterial : Material { public const string ClassName = "TerrainMaterial"; @@ -26,8 +26,22 @@ internal class TerrainPbrMaterial : Material public ReadOnlyCollection Levels { get; } - public TerrainPbrMaterial(JsonDict dict) : base(dict) + public TerrainMaterial(JsonDict dict) : base(dict) { + if (!InternalName.Exists && !Name.Exists) + { + throw new ArgumentException("Neither name nor internalName found in dict."); + } + + if (!InternalName.Exists) + { + InternalName.Value = Name.Value; + } + else + { + Name.Value = InternalName.Value; + } + GroundModel = new(this, "groundmodelName"); BaseColor = new(this, "baseColor"); @@ -48,9 +62,22 @@ public TerrainPbrMaterial(JsonDict dict) : base(dict) ]); } - public void NormalizeSquareSize(float squareSize) + public void MultiplyMappingScale(float factor) { + foreach (var level in Levels) + { + if (level.IsTextureEmpty) + continue; + + float scale = level.MappingScale.Value; + + scale *= factor; + if (scale < 1) + scale = 1; + + level.MappingScale.Value = (int)scale; + } } public void CreatePersistentId() @@ -65,27 +92,27 @@ public override void ResolveTexturePaths(MaterialLibary libary, string source) { if (level.IsTextureEmpty) continue; - var key = libary.Textures.Register(level.Texture.Value, source); + var key = libary.Textures.RegisterRelative(level.Texture.Value, source); level.Texture.Value = Path.Combine(libary.TexturesPath, key); } } - public override Material Copy() + public override TerrainMaterial Copy() { var copy = new JsonDict(Dict); - return new TerrainPbrMaterial(copy); + return new TerrainMaterial(copy); } } internal class TerrainMaterialDistances { public string Prefix { get; } - public TerrainPbrMaterial Owner { get; } + public TerrainMaterial Owner { get; } public JsonDictProperty Distances { get; } public JsonDictProperty DistanceAttenuation { get; } - public TerrainMaterialDistances(TerrainPbrMaterial owner, string prefix, float[] distances, Vector2 vector) + public TerrainMaterialDistances(TerrainMaterial owner, string prefix, float[] distances, Vector2 vector) { Owner = owner; Prefix = prefix; @@ -112,33 +139,33 @@ public TerrainMaterialDistances(TerrainPbrMaterial owner, string prefix, float[] internal class TerrainMaterialTexture { public string Prefix { get; } - public TerrainPbrMaterial Owner { get; } + public TerrainMaterial Owner { get; } public TerrainMaterialTextureLayer Base { get; } public TerrainMaterialTextureLayer Macro { get; } public TerrainMaterialTextureLayer Detail { get; } - public TerrainMaterialTexture(TerrainPbrMaterial owner, string prefix) + public TerrainMaterialTexture(TerrainMaterial owner, string prefix) { Owner = owner; Prefix = prefix; - Base = new(this, "Base"); - Macro = new(this, "Macro"); - Detail = new(this, "Detail"); + Base = new(this, "Base", 256); + Macro = new(this, "Macro", 60); + Detail = new(this, "Detail", 2); } } internal class TerrainMaterialTextureLayer { public string Prefix { get; } - public TerrainPbrMaterial Owner { get; } + public TerrainMaterial Owner { get; } public JsonDictProperty Strength { get; } public JsonDictProperty MappingScale { get; } public JsonDictProperty Texture { get; } - public TerrainMaterialTextureLayer(TerrainMaterialTexture owner, string prefix) + public TerrainMaterialTextureLayer(TerrainMaterialTexture owner, string prefix, int texSize) { Owner = owner.Owner; Prefix = owner.Prefix + prefix; @@ -148,11 +175,19 @@ public TerrainMaterialTextureLayer(TerrainMaterialTexture owner, string prefix) var strengthKey = Prefix + "Strength"; Texture = new(Owner, texKey); - MappingScale = new(Owner, texSizeKey); + MappingScale = new(Owner, texSizeKey, texSize); Strength = new(Owner, strengthKey); Strength.SetIfEmpty(Vector2.One); } - public bool IsTextureEmpty => string.IsNullOrEmpty(Texture.Value); + public bool IsTextureEmpty + { + get + { + if (!Texture.Exists) + return true; + return string.IsNullOrEmpty(Texture.Value); + } + } } \ No newline at end of file diff --git a/SceneTree/Art/TerrainMaterialLibary.cs b/SceneTree/Art/TerrainMaterialLibary.cs new file mode 100644 index 0000000..08b1f9c --- /dev/null +++ b/SceneTree/Art/TerrainMaterialLibary.cs @@ -0,0 +1,39 @@ +using LevelTemplateCreator.Assets; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.SceneTree.Art; + +internal class TerrainMaterialLibary : MaterialLibary +{ + readonly float _squareSize; + + public TerrainMaterialLibary(string path, float squareSize) : base(path) + { + _squareSize = squareSize; + } + + public override void AddAsset(TAsset asset) + { + float squareSize = asset switch + { + TerrainMaterialAsset tma => tma.SquareSize, + _ => 1 + }; + + var copy = asset.GetCopy(); + copy.CreatePersistentId(); + copy.MultiplyMappingScale(squareSize / _squareSize); + copy.ResolveTexturePaths(this, asset.SourceFile); + Materials.Add(copy); + } + + public void CreateTerrainMaterialTextureSet(string name) + { + Misc.Add(new TerrainMaterialTextureSet(name)); + } +} diff --git a/SceneTree/Art/TerrainPbrMaterialTextureSet.cs b/SceneTree/Art/TerrainMaterialTextureSet.cs similarity index 84% rename from SceneTree/Art/TerrainPbrMaterialTextureSet.cs rename to SceneTree/Art/TerrainMaterialTextureSet.cs index 286422c..6b0742c 100644 --- a/SceneTree/Art/TerrainPbrMaterialTextureSet.cs +++ b/SceneTree/Art/TerrainMaterialTextureSet.cs @@ -7,13 +7,13 @@ namespace LevelTemplateCreator.SceneTree.Art; -internal class TerrainPbrMaterialTextureSet : JsonDictWrapper +internal class TerrainMaterialTextureSet : JsonDictWrapper { public JsonDictProperty BaseTexSize { get; } public JsonDictProperty DetailTexSize { get; } public JsonDictProperty MacroTexSize { get; } - public TerrainPbrMaterialTextureSet(string name) : base(new JsonDict()) + public TerrainMaterialTextureSet(string name) : base(new JsonDict()) { Class.Value = "TerrainMaterialTextureSet"; Name.Value = name; diff --git a/SceneTree/JsonDictProperty.cs b/SceneTree/JsonDictProperty.cs index b6d6c77..c175940 100644 --- a/SceneTree/JsonDictProperty.cs +++ b/SceneTree/JsonDictProperty.cs @@ -11,23 +11,23 @@ namespace LevelTemplateCreator.SceneTree; struct JsonDictProperty { - private readonly JsonDictWrapper _owner; - public string Key { get; } + public readonly JsonDictWrapper Owner; + public readonly string Key; public JsonDictProperty(JsonDictWrapper owner, string key) { - _owner = owner; + Owner = owner; Key = key; } - public object Value { get => _owner[Key]; set => _owner[Key] = value; } + public object Value { get => Owner[Key]; set => Owner[Key] = value; } - public bool Exists => _owner.Dict.ContainsKey(Key); + public bool Exists => Owner.Dict.ContainsKey(Key); - public void Remove() => _owner.Dict.Remove(Key); + public void Remove() => Owner.Dict.Remove(Key); public void Vector2(Vector2 vec) { - if (_owner.TryGetValue(Key, out var array)) + if (Owner.TryGetValue(Key, out var array)) { array[0] = vec.X; array[1] = vec.Y; } @@ -45,7 +45,7 @@ public Vector2 Vector2() public void Vector3(Vector3 vec) { - if (_owner.TryGetValue(Key, out var array)) + if (Owner.TryGetValue(Key, out var array)) { array[0] = vec.X; array[1] = vec.Y; array[2] = vec.Z; } @@ -88,6 +88,8 @@ enum PropertyType public bool Exists => _property.Exists; + public T? DefaultValue { get; } + public T Value { get => Get();set => Set(value); } public JsonDictProperty(JsonDictWrapper owner, string key) @@ -107,6 +109,11 @@ public JsonDictProperty(JsonDictWrapper owner, string key) _type = PropertyType.Object; } + public JsonDictProperty(JsonDictWrapper owner, string key, T defaultValue) : this(owner, key) + { + DefaultValue = defaultValue; + } + public void Remove() => _property.Remove(); public void Set(T value) @@ -143,10 +150,12 @@ public T Get() { if (!_property.Exists) { - var value = (T)default!; - if (value == null) - throw new InvalidOperationException(_property.Key); - return value; + if (DefaultValue != null) + { + return DefaultValue; + } + var msg = $"Failed to acces property '{_property.Key}' of type '{typeof(T).FullName}'."; + throw new InvalidOperationException(msg); } switch (_type) diff --git a/SceneTree/JsonDictWrapper.cs b/SceneTree/JsonDictWrapper.cs index ecd3c37..248c431 100644 --- a/SceneTree/JsonDictWrapper.cs +++ b/SceneTree/JsonDictWrapper.cs @@ -5,13 +5,14 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using LevelTemplateCreator.Collections; using LevelTemplateCreator.IO; using LevelTemplateCreator.SceneTree.Main; namespace LevelTemplateCreator.SceneTree; -internal class JsonDictWrapper +internal class JsonDictWrapper : IKeyed { public JsonDict Dict { get; } @@ -22,10 +23,12 @@ public object this[string key] } public JsonDictProperty Class { get; } - public JsonDictProperty Name { get; } public JsonDictProperty InternalName { get; } + public JsonDictProperty Name { get; } public JsonDictProperty PersistentId { get; } + string IKeyed.Key => Name.Exists ? Name.Value : string.Empty; + public JsonDictWrapper(JsonDict dict) { Dict = dict; @@ -85,4 +88,30 @@ public virtual void CopyTo(JsonDictWrapper target) } } -} + public void ApplyNamespace(string @namespace) + { + if (!string.IsNullOrEmpty(@namespace)) + { + ApplyPrefix(@namespace); + } + } + + public virtual void ApplyPrefix(string prefix) + { + if (Name.Exists) + { + Name.Value = prefix + Name.Value; + } + if (InternalName.Exists) + { + InternalName.Value = prefix + InternalName.Value; + } + } + + public virtual JsonDictWrapper Copy() + { + var dict = new JsonDict(Dict); + return new JsonDictWrapper(dict); + } + +} \ No newline at end of file diff --git a/SceneTree/Main/GroundCover.cs b/SceneTree/Main/GroundCover.cs index 45e9c2e..0915bf9 100644 --- a/SceneTree/Main/GroundCover.cs +++ b/SceneTree/Main/GroundCover.cs @@ -8,17 +8,39 @@ namespace LevelTemplateCreator.SceneTree.Main; internal class GroundCover : SimItem { - public const string ClassName = "GroundCover_Definition"; + public const string ClassName = "GroundCover"; public JsonDictProperty Material { get; } + public JsonDictProperty Types { get; } + public GroundCover(JsonDict dict) : base(dict) { Material = new(this, "material"); + + Types = new(this, "Types"); + } + + public override GroundCover Copy() + { + if (Types.Exists) + { + throw new Exception(); + } + + var dict = new JsonDict(Dict); + return new GroundCover(dict); } public void AddInstance(GroundCoverInstance instance) { } + + public override void ApplyPrefix(string prefix) + { + base.ApplyPrefix(prefix); + + Material.Value = prefix + Material.Value; + } } diff --git a/SceneTree/Main/GroundCoverInstance.cs b/SceneTree/Main/GroundCoverInstance.cs index a7aacfd..1c0e98c 100644 --- a/SceneTree/Main/GroundCoverInstance.cs +++ b/SceneTree/Main/GroundCoverInstance.cs @@ -23,31 +23,44 @@ public GroundCoverInstance(JsonDict dict) : base(dict) public static GroundCoverInstance[] PopFromGroundcover(GroundCover obj) { - return PopFromObject(obj, "Types", "parent"); + return PopFromObject(obj); } - public static GroundCoverInstance[] PopFromMaterial(TerrainPbrMaterial obj) + static GroundCoverInstance[] PopFromObject(JsonDictWrapper obj) { - return PopFromObject(obj, "groundcover", "layer"); - } - - static GroundCoverInstance[] PopFromObject(JsonDictWrapper obj, string name, string parent) - { - var array = new JsonDictProperty(obj, name); + var array = new JsonDictProperty(obj, "Types"); if (!array.Exists) return Array.Empty(); - var result = new GroundCoverInstance[array.Value.Length]; + var result = new List(); + for (int i = 0; i < array.Value.Length; i++) { - var instance = new GroundCoverInstance(array.Value[i]); - instance[parent] = obj.Name.Value; - result[i] = instance; + var dict = array.Value[i]; + if (dict.Count == 0) + continue; + + var instance = new GroundCoverInstance(dict); + instance["parent"] = obj.Name.Value; + result.Add(instance); } array.Remove(); - return result; + return result.ToArray(); + } + + public override GroundCoverInstance Copy() + { + var dict = new JsonDict(Dict); + return new GroundCoverInstance(dict); + } + + public override void ApplyPrefix(string prefix) + { + base.ApplyPrefix(prefix); + + Layer.Value = prefix + Layer.Value; } } diff --git a/SceneTree/Main/SimGroup.cs b/SceneTree/Main/SimGroup.cs index 9509ce5..5b8e6e0 100644 --- a/SceneTree/Main/SimGroup.cs +++ b/SceneTree/Main/SimGroup.cs @@ -1,47 +1,24 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; + using System.Linq; using System.Text; using System.Threading.Tasks; +using LevelTemplateCreator.Collections; + namespace LevelTemplateCreator.SceneTree.Main; internal class SimGroup : SimItem { - public class SimGroupItems : IReadOnlyList - { - List _items; - - public SimGroupItems() { - _items = new List(); - } - - public int Count => _items.Count; - - public SimItem this[int index] => _items[index]; - - public void Add(params SimItem[] items) - { - foreach (var item in items) - { - _items.Add(item); - } - } - - IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator(); - - public IEnumerator GetEnumerator() => _items.GetEnumerator(); - } - public bool IsMain { get; set; } = false; - public SimGroupItems Items { get; } + public KeyedCollection Items { get; } public SimGroup(JsonDict dict) : base(dict) { - Items = new SimGroupItems(); + Items = new(); } public SimGroup(string name) : this(new JsonDict()) diff --git a/SceneTree/Main/SimGroupMissionGroup.cs b/SceneTree/Main/SimGroupMissionGroup.cs index 2430c34..3448858 100644 --- a/SceneTree/Main/SimGroupMissionGroup.cs +++ b/SceneTree/Main/SimGroupMissionGroup.cs @@ -10,10 +10,13 @@ internal class SimGroupMissionGroup : SimGroup { public SimGroupLevelObject LevelObject { get; } + public SimGroup PlayerDropPoints { get; } + public SimGroupMissionGroup() : base("MissionGroup") { LevelObject = new SimGroupLevelObject(); + PlayerDropPoints = new SimGroup("PlayerDopPoints"); - Items.Add(LevelObject); + Items.Add(LevelObject, PlayerDropPoints); } } diff --git a/SceneTree/Main/SpawnSphere.cs b/SceneTree/Main/SpawnSphere.cs new file mode 100644 index 0000000..2570213 --- /dev/null +++ b/SceneTree/Main/SpawnSphere.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LevelTemplateCreator.SceneTree.Main; + +internal class SpawnSphere : SimItem +{ + public JsonDictProperty DataBlock { get; } + + public SpawnSphere(JsonDict dict) : base(dict) + { + DataBlock = new(this, "dataBlock"); + } + + public SpawnSphere(float height) : this(new JsonDict()) + { + Name.Value = "spawn_default"; + Class.Value = "SpawnSphere"; + DataBlock.Value = "SpawnSphereMarker"; + Position.Value = new System.Numerics.Vector3(0, 0, height); + } + + /* + "name": "spawn_default", + "class": "SpawnSphere", + "position": [ + 0, + 0, + 0 + ], + "autoplaceOnSpawn": "0", + "dataBlock": "SpawnSphereMarker", + "enabled": "1", + "homingCount": "0", + "indoorWeight": "1", + "isAIControlled": "0", + "lockCount": "0", + "outdoorWeight": "1", + "radius": 1, + "rotationMatrix": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "sphereWeight": "1" + */ +} diff --git a/SceneTree/Main/TerrainBlock.cs b/SceneTree/Main/TerrainBlock.cs index 0af48e3..ba3a925 100644 --- a/SceneTree/Main/TerrainBlock.cs +++ b/SceneTree/Main/TerrainBlock.cs @@ -11,7 +11,7 @@ internal class TerrainBlock : SimItem public JsonDictProperty MaterialTextureSet { get; } public JsonDictProperty TerrainFile { get; } public JsonDictProperty BaseTexSize { get; } - public JsonDictProperty MaxHeight { get; } + public JsonDictProperty MaxHeight { get; } public JsonDictProperty SquareSize { get; } public TerrainBlock(JsonDict dict) : base(dict) diff --git a/TerrainInfo.cs b/TerrainInfo.cs index 1a643d8..f79dd03 100644 --- a/TerrainInfo.cs +++ b/TerrainInfo.cs @@ -19,6 +19,7 @@ public TerrainInfo() size = 1024; squareSize = 1; MaxHeight = 512; + Height = 10; } public int Resolution @@ -51,5 +52,7 @@ public float WorldSize } } - public int MaxHeight { get; set; } + public float MaxHeight { get; set; } + + public float Height { get; set; } }