├── .editorconfig ├── .gitattributes ├── .gitignore ├── 010 Editor Binary Template ├── AuroraAssetTemplate.bt └── FSDAssetTemplate.bt ├── AuroraAssetEditor.sln ├── AuroraAssetEditor ├── App.xaml ├── App.xaml.cs ├── AuroraAsset.dll ├── AuroraAssetEditor.csproj ├── Classes │ ├── AuroraAsset.cs │ ├── AuroraAssetDll.cs │ ├── AuroraDbManager.cs │ ├── FSDAsset.cs │ ├── FTPOperations.cs │ ├── InternetArchiveAssetDownloader.cs │ ├── StatusArgs.cs │ ├── ThreadSafeObservableCollection.cs │ ├── WpfControlThreadingExtensions.cs │ ├── XboxAssetDownloader.cs │ └── XboxUnity.cs ├── Controls │ ├── BackgroundControl.xaml │ ├── BackgroundControl.xaml.cs │ ├── BoxartControl.xaml │ ├── BoxartControl.xaml.cs │ ├── CircularProgressBar.xaml │ ├── CircularProgressBar.xaml.cs │ ├── FtpAssetsControl.xaml │ ├── FtpAssetsControl.xaml.cs │ ├── IconBannerControl.xaml │ ├── IconBannerControl.xaml.cs │ ├── OnlineAssetsControl.xaml │ ├── OnlineAssetsControl.xaml.cs │ ├── ScreenshotsControl.xaml │ └── ScreenshotsControl.xaml.cs ├── Helpers │ └── GlobalState.cs ├── InputDialog.xaml ├── InputDialog.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Models │ └── Game.cs ├── Resources │ ├── Placeholders │ │ ├── background.png │ │ ├── banner.png │ │ ├── cover.png │ │ ├── icon.png │ │ └── screenshot.png │ └── icon.ico ├── TitleAndDbIdDialog.xaml ├── TitleAndDbIdDialog.xaml.cs └── msvcr100.dll ├── CHANGELOG.txt ├── LICENSE ├── README.md ├── SQLite.Interop └── x86 │ └── SQLite.Interop.dll ├── appveyor.yml └── tools └── ParseLocale.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # 2 | # https://editorconfig.org/#file-format-details 3 | # https://docs.microsoft.com/en-us/visualstudio/ide/cpp-editorconfig-properties?view=vs-2019 4 | # https://stackoverflow.com/questions/51356453/export-visual-studios-code-style-settings-as-editorconfig 5 | # 6 | 7 | ##################### 8 | ### Core Settings ### 9 | ##################### 10 | root = true 11 | 12 | # All files 13 | [*] 14 | 15 | end_of_line = crlf 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.cs] 20 | 21 | charset = utf-8-bom 22 | 23 | indent_style = tab 24 | indent_size = 4 25 | tab_width = 4 26 | 27 | #### .NET Coding Conventions #### 28 | 29 | # Organize usings 30 | dotnet_separate_import_directive_groups = false 31 | dotnet_sort_system_directives_first = true 32 | file_header_template = unset 33 | 34 | # this. and Me. preferences 35 | dotnet_style_qualification_for_event = false 36 | dotnet_style_qualification_for_field = false 37 | dotnet_style_qualification_for_method = false 38 | dotnet_style_qualification_for_property = false 39 | 40 | # Language keywords vs BCL types preferences 41 | dotnet_style_predefined_type_for_locals_parameters_members = false:silent 42 | dotnet_style_predefined_type_for_member_access = false:silent 43 | 44 | # Parentheses preferences 45 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 46 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 47 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 48 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 49 | 50 | # Modifier preferences 51 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 52 | 53 | # Expression-level preferences 54 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 55 | dotnet_style_coalesce_expression = true:suggestion 56 | dotnet_style_null_propagation = true:suggestion 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 58 | dotnet_style_prefer_auto_properties = true:silent 59 | dotnet_style_object_initializer = true:suggestion 60 | dotnet_style_collection_initializer = true:suggestion 61 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 62 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 63 | dotnet_style_prefer_conditional_expression_over_return = true:silent 64 | dotnet_style_explicit_tuple_names = true:suggestion 65 | dotnet_style_prefer_inferred_tuple_names = false:suggestion 66 | dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion 67 | dotnet_style_prefer_compound_assignment = true:suggestion 68 | dotnet_style_prefer_simplified_interpolation = true:suggestion 69 | dotnet_style_namespace_match_folder = true:suggestion 70 | 71 | # Field preferences 72 | dotnet_style_readonly_field = true:suggestion 73 | 74 | # Parameter preferences 75 | dotnet_code_quality_unused_parameters = all:suggestion 76 | 77 | # Suppression preferences 78 | dotnet_remove_unnecessary_suppression_exclusions = none 79 | 80 | # New line preferences 81 | dotnet_style_allow_multiple_blank_lines_experimental = true:silent 82 | dotnet_style_allow_statement_immediately_after_block_experimental = true:silent 83 | 84 | #### C# Coding Conventions #### 85 | 86 | csharp_style_prefer_top_level_statements = true:silent 87 | csharp_style_prefer_tuple_swap = true:suggestion 88 | csharp_style_prefer_utf8_string_literals = true:suggestion 89 | csharp_style_prefer_readonly_struct = true:suggestion 90 | csharp_style_prefer_readonly_struct_member = true:suggestion 91 | csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent 92 | csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent 93 | 94 | # var preferences 95 | csharp_style_var_elsewhere = false:silent 96 | csharp_style_var_for_built_in_types = false:silent 97 | csharp_style_var_when_type_is_apparent = false:silent 98 | 99 | # Expression-bodied members 100 | csharp_style_expression_bodied_accessors = true:silent 101 | csharp_style_expression_bodied_constructors = false:silent 102 | csharp_style_expression_bodied_indexers = true:silent 103 | csharp_style_expression_bodied_lambdas = true:silent 104 | csharp_style_expression_bodied_local_functions = when_on_single_line:silent 105 | csharp_style_expression_bodied_methods = when_on_single_line:silent 106 | csharp_style_expression_bodied_operators = true:silent 107 | csharp_style_expression_bodied_properties = true:silent 108 | 109 | # Pattern matching preferences 110 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 111 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 112 | csharp_style_prefer_not_pattern = true:suggestion 113 | csharp_style_prefer_pattern_matching = true:silent 114 | csharp_style_prefer_switch_expression = true:suggestion 115 | csharp_style_prefer_extended_property_pattern = true:suggestion 116 | 117 | # Null-checking preferences 118 | csharp_style_conditional_delegate_call = true:suggestion 119 | 120 | # Modifier preferences 121 | csharp_prefer_static_local_function = true:suggestion 122 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async 123 | 124 | # Code-block preferences 125 | csharp_prefer_braces = true:silent 126 | csharp_prefer_simple_using_statement = true:suggestion 127 | csharp_style_namespace_declarations = block_scoped:silent 128 | csharp_style_prefer_method_group_conversion = true:silent 129 | 130 | # Expression-level preferences 131 | csharp_prefer_simple_default_expression = true:suggestion 132 | csharp_style_deconstructed_variable_declaration = false:suggestion 133 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 134 | csharp_style_inlined_variable_declaration = true:suggestion 135 | csharp_style_pattern_local_over_anonymous_function = true 136 | csharp_style_prefer_index_operator = true:suggestion 137 | csharp_style_prefer_range_operator = true:suggestion 138 | csharp_style_throw_expression = true:suggestion 139 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 140 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 141 | csharp_style_prefer_null_check_over_type_check = true:suggestion 142 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 143 | 144 | # 'using' directive preferences 145 | csharp_using_directive_placement = outside_namespace:silent 146 | 147 | # New line preferences 148 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent 149 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent 150 | csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent 151 | 152 | #### C# Formatting Rules #### 153 | 154 | # New line preferences 155 | csharp_new_line_before_catch = true 156 | csharp_new_line_before_else = true 157 | csharp_new_line_before_finally = true 158 | csharp_new_line_before_members_in_anonymous_types = true 159 | csharp_new_line_before_members_in_object_initializers = true 160 | csharp_new_line_before_open_brace = all 161 | csharp_new_line_between_query_expression_clauses = true 162 | 163 | # Indentation preferences 164 | csharp_indent_block_contents = true 165 | csharp_indent_braces = false 166 | csharp_indent_case_contents = true 167 | csharp_indent_case_contents_when_block = false 168 | csharp_indent_labels = one_less_than_current 169 | csharp_indent_switch_labels = true 170 | 171 | # Space preferences 172 | csharp_space_after_cast = false 173 | csharp_space_after_colon_in_inheritance_clause = true 174 | csharp_space_after_comma = true 175 | csharp_space_after_dot = false 176 | csharp_space_after_keywords_in_control_flow_statements = true 177 | csharp_space_after_semicolon_in_for_statement = true 178 | csharp_space_around_binary_operators = before_and_after 179 | csharp_space_around_declaration_statements = false 180 | csharp_space_before_colon_in_inheritance_clause = true 181 | csharp_space_before_comma = false 182 | csharp_space_before_dot = false 183 | csharp_space_before_open_square_brackets = false 184 | csharp_space_before_semicolon_in_for_statement = false 185 | csharp_space_between_empty_square_brackets = false 186 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 187 | csharp_space_between_method_call_name_and_opening_parenthesis = false 188 | csharp_space_between_method_call_parameter_list_parentheses = false 189 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 190 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 191 | csharp_space_between_method_declaration_parameter_list_parentheses = false 192 | csharp_space_between_parentheses = false 193 | csharp_space_between_square_brackets = false 194 | 195 | # Wrapping preferences 196 | csharp_preserve_single_line_blocks = true 197 | csharp_preserve_single_line_statements = true 198 | 199 | #### Naming styles #### 200 | 201 | # Naming rules 202 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 203 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 204 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 205 | 206 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 207 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 208 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 209 | 210 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 211 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 212 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 213 | 214 | # Symbol specifications 215 | dotnet_naming_symbols.interface.applicable_kinds = interface 216 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 217 | dotnet_naming_symbols.interface.required_modifiers = 218 | 219 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 220 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 221 | dotnet_naming_symbols.types.required_modifiers = 222 | 223 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 224 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 225 | dotnet_naming_symbols.non_field_members.required_modifiers = 226 | 227 | # Naming styles 228 | dotnet_naming_style.pascal_case.required_prefix = 229 | dotnet_naming_style.pascal_case.required_suffix = 230 | dotnet_naming_style.pascal_case.word_separator = 231 | dotnet_naming_style.pascal_case.capitalization = pascal_case 232 | 233 | dotnet_naming_style.begins_with_i.required_prefix = I 234 | dotnet_naming_style.begins_with_i.required_suffix = 235 | dotnet_naming_style.begins_with_i.word_separator = 236 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 237 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | /AuroraAssetEditor/*.DotSettings 198 | -------------------------------------------------------------------------------- /010 Editor Binary Template/AuroraAssetTemplate.bt: -------------------------------------------------------------------------------- 1 | //-------------------------------------- 2 | //--- 010 Editor v5.0.2 Binary Template 3 | // 4 | // File: AuroraAssetTemplate.bt 5 | // Author: MasterRowen & Swizzy 6 | // Revision: 1 7 | // Purpose: Aurora's .asset files 8 | //-------------------------------------- 9 | #define ASSET_SCREENSHOT_MAX 20 10 | 11 | typedef enum { 12 | ASSET_ICON, 13 | ASSET_BANNER, 14 | ASSET_BOXART, // Covers basically 15 | ASSET_SLOT, 16 | ASSET_BACKGROUND, 17 | ASSET_SCREENSHOT_START, 18 | ASSET_SCREENSHOT = ASSET_SCREENSHOT_START, 19 | ASSET_SCREENSHOT_END = ASSET_SCREENSHOT_START + ASSET_SCREENSHOT_MAX, 20 | ASSET_END = ASSET_SCREENSHOT_END, 21 | ASSET_MAX = ASSET_END 22 | } ASSET_TYPE; 23 | 24 | typedef struct { 25 | DWORD dwMagic; // Should be 'RXEA' 26 | DWORD dwVersion; // Should be 1 27 | DWORD dwDataSize; 28 | } ASSET_PACK_HEADER; 29 | 30 | typedef struct { 31 | DWORD Common; 32 | DWORD ReferenceCount; // Should be 0 33 | DWORD Fence; // Should be 0 34 | DWORD ReadFence; // Should be 0 35 | DWORD Identifier; // Should be 0 36 | DWORD BaseFlush; // Should be 0xFFFF0000 37 | DWORD MipFlush; // Should be 0xFFFF0000 38 | union { 39 | struct { 40 | struct { 41 | DWORD Tiled : 1; // BOOL 42 | DWORD Pitch : 9; // DWORD 43 | DWORD : 1; 44 | DWORD : 2; 45 | DWORD ClampZ : 3; // GPUCLAMP 46 | DWORD ClampY : 3; // GPUCLAMP 47 | DWORD ClampX : 3; // GPUCLAMP 48 | DWORD SignW : 2; // GPUSIGN 49 | DWORD SignZ : 2; // GPUSIGN 50 | DWORD SignY : 2; // GPUSIGN 51 | DWORD SignX : 2; // GPUSIGN 52 | DWORD Type : 2; // GPUCONSTANTTYPE 53 | } GPU_FETCH_CONSTANT_0; 54 | struct { 55 | DWORD BaseAddress : 20; // DWORD 56 | DWORD ClampPolicy : 1; // GPUCLAMPPOLICY 57 | DWORD Stack : 1; // BOOL 58 | DWORD RequestSize : 2; // GPUREQUESTSIZE 59 | DWORD Endian : 2; // GPUENDIAN 60 | DWORD DataFormat : 6; // GPUTEXTUREFORMAT 61 | } GPU_FETCH_CONSTANT_1; 62 | union 63 | { 64 | struct { 65 | DWORD : 8; 66 | DWORD Width : 24; // DWORD 67 | } OneD; 68 | struct { 69 | DWORD : 6; 70 | DWORD Height : 13; // DWORD 71 | DWORD Width : 13; // DWORD 72 | } TwoD; 73 | struct { 74 | DWORD Depth : 10; // DWORD 75 | DWORD Height : 11; // DWORD 76 | DWORD Width : 11; // DWORD 77 | } ThreeD; 78 | struct { 79 | DWORD Depth : 6; // DWORD 80 | DWORD Height : 13; // DWORD 81 | DWORD Width : 13; // DWORD 82 | } Stack; 83 | } Size; 84 | struct { 85 | DWORD BorderSize : 1; // DWORD 86 | DWORD : 3; 87 | DWORD AnisoFilter : 3; // GPUANISOFILTER 88 | DWORD MipFilter : 2; // GPUMIPFILTER 89 | DWORD MinFilter : 2; // GPUMINMAGFILTER 90 | DWORD MagFilter : 2; // GPUMINMAGFILTER 91 | INT ExpAdjust : 6; // int 92 | DWORD SwizzleW : 3; // GPUSWIZZLE 93 | DWORD SwizzleZ : 3; // GPUSWIZZLE 94 | DWORD SwizzleY : 3; // GPUSWIZZLE 95 | DWORD SwizzleX : 3; // GPUSWIZZLE 96 | DWORD NumFormat : 1; // GPUNUMFORMAT 97 | } GPUTEXTURE_FETCH_CONSTANT_3; 98 | struct { 99 | INT GradExpAdjustV : 5; // int 100 | INT GradExpAdjustH : 5; // int 101 | INT LODBias : 10; // int 102 | DWORD MinAnisoWalk : 1; // BOOL 103 | DWORD MagAnisoWalk : 1; // BOOL 104 | DWORD MaxMipLevel : 4; // DWORD 105 | DWORD MinMipLevel : 4; // DWORD 106 | DWORD VolMinFilter : 1; // GPUMINMAGFILTER 107 | DWORD VolMagFilter : 1; // GPUMINMAGFILTER 108 | } GPUTEXTURE_FETCH_CONSTANT_4; 109 | struct { 110 | DWORD MipAddress : 20; // DWORD 111 | DWORD PackedMips : 1; // BOOL 112 | DWORD Dimension : 2; // GPUDIMENSION 113 | INT AnisoBias : 4; // int 114 | DWORD TriClamp : 2; // GPUTRICLAMP 115 | DWORD ForceBCWToMax : 1; // BOOL 116 | DWORD BorderColor : 2; // GPUBORDERCOLOR 117 | } GPUTEXTURE_FETCH_CONSTANT_5; 118 | } GPUTEXTURE_FETCH_CONSTANT; 119 | DWORD dword[6]; 120 | } GPU_FETCH_CONSTANT; 121 | } ASSET_PACK_TEXTURE_HEADER; 122 | 123 | typedef struct { 124 | DWORD Offset; 125 | DWORD Size; 126 | DWORD ExtendedInfo; // It's a pointer, ignore the value, or save it as 0 127 | ASSET_PACK_TEXTURE_HEADER TextureHeader; 128 | } ASSET_PACK_ENTRY; 129 | 130 | typedef struct { 131 | DWORD Flags; 132 | DWORD ScreenshotCount; 133 | ASSET_PACK_ENTRY Entries[ASSET_MAX]; 134 | } ASSET_PACK_ENTRY_TABLE; 135 | 136 | typedef struct { 137 | BYTE ALPHA; 138 | BYTE RED; 139 | BYTE GREEN; 140 | BYTE BLUE; 141 | } COLOR; 142 | 143 | // Actual shown data starts here 144 | 145 | ASSET_PACK_HEADER Header; 146 | Assert(Header.dwMagic == 0x52584541, "Invalid header Magic, expected 'RXEA'"); 147 | Assert(Header.dwVersion == 1, "Invalid header Version, expected 1"); 148 | ASSET_PACK_ENTRY_TABLE EntryTable; 149 | BYTE Padding[2048 - (FTell() % 2048)]; 150 | local ASSET_TYPE x; 151 | for( x = 0; x < ASSET_MAX; x++ ) { 152 | if( EntryTable.Entries[x].Size > 0 ) { 153 | typedef struct { 154 | COLOR ImageData[EntryTable.Entries[x].Size/sizeof(COLOR)]; 155 | } IMAGE_DATA; 156 | IMAGE_DATA Image; 157 | } 158 | } -------------------------------------------------------------------------------- /010 Editor Binary Template/FSDAssetTemplate.bt: -------------------------------------------------------------------------------- 1 | //-------------------------------------- 2 | //--- 010 Editor v5.0.2 Binary Template 3 | // 4 | // File: FSDAssetTemplate.bt 5 | // Author: Swizzy, Special thanks to MaesterRowen for providing the information within 6 | // Revision: 1 7 | // Purpose: FSD's .asset files 8 | //-------------------------------------- 9 | 10 | typedef enum { 11 | Thumbnail = 0x01, 12 | Background = 0x02, 13 | Banner = 0x04, 14 | Boxart = 0x08, 15 | Preview = 0x10, 16 | Screenshot = 0x20, 17 | Slot = 0x40, 18 | FullCover = 0x80 19 | } CONTENT_ASSET_TYPES; 20 | 21 | typedef struct { 22 | DWORD Magic; 23 | DWORD Version; 24 | DWORD Reserved; 25 | DWORD AssetFlags; 26 | DWORD AssetCount; 27 | DWORD ScreenshotCount; 28 | } CONTENT_ASSET_HEADER; 29 | 30 | typedef struct { 31 | CONTENT_ASSET_TYPES AssetType; 32 | DWORD Offset; 33 | DWORD Size; 34 | DWORD TotalSize; 35 | } CONTENT_ASSET_ENTRY; 36 | 37 | typedef struct _CONTENT_ASSET_SCREENSHOT_ENTRY { 38 | DWORD Offset; 39 | DWORD Size; 40 | DWORD TotalSize; 41 | DWORD Reserved; 42 | } CONTENT_ASSET_SCREENSHOT_ENTRY; 43 | 44 | CONTENT_ASSET_HEADER Header; 45 | Assert(Header.Magic == 0x46534441, "Invalid header Magic, expected 'RXEA'"); 46 | Assert(Header.Version == 1, "Invalid header Version, expected 1"); 47 | CONTENT_ASSET_ENTRY Entries[10]; 48 | CONTENT_ASSET_SCREENSHOT_ENTRY Screenshots[20]; -------------------------------------------------------------------------------- /AuroraAssetEditor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33829.357 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuroraAssetEditor", "AuroraAssetEditor\AuroraAssetEditor.csproj", "{7EBB95B2-CB56-4263-9C2B-601E0FC36001}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E7B130E9-33B7-48A5-BDC8-B2DB74B0128D}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | appveyor.yml = appveyor.yml 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x86 = Debug|x86 18 | Release|Any CPU = Release|Any CPU 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Debug|x86.ActiveCfg = Debug|x86 25 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Debug|x86.Build.0 = Debug|x86 26 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Release|x86.ActiveCfg = Release|x86 29 | {7EBB95B2-CB56-4263-9C2B-601E0FC36001}.Release|x86.Build.0 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {6E09DD1D-9C76-46F0-B0F2-B665D49308B6} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /AuroraAssetEditor/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | -------------------------------------------------------------------------------- /AuroraAssetEditor/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // App.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 08/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor { 9 | using System.Drawing; 10 | using System.IO; 11 | using System.Reflection; 12 | using System.Windows; 13 | using System.Windows.Interop; 14 | using System.Windows.Media; 15 | using System.Windows.Media.Imaging; 16 | using Classes; 17 | 18 | /// 19 | /// Interaction logic for App.xaml 20 | /// 21 | public partial class App { 22 | internal static readonly FtpOperations FtpOperations = new FtpOperations(); 23 | 24 | private static readonly Icon Icon = 25 | Icon.ExtractAssociatedIcon(Path.Combine(Path.GetDirectoryName(Assembly.GetAssembly(typeof(App)).Location), Path.GetFileName(Assembly.GetAssembly(typeof(App)).Location))); 26 | 27 | internal static readonly ImageSource WpfIcon = Imaging.CreateBitmapSourceFromHIcon(Icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 28 | 29 | private void AppStart(object sender, StartupEventArgs e) { new MainWindow(e.Args).Show(); } 30 | } 31 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/AuroraAsset.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/AuroraAsset.dll -------------------------------------------------------------------------------- /AuroraAssetEditor/AuroraAssetEditor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WinExe 6 | true 7 | net48 8 | 9 | AnyCPU;x86 10 | AnyCPU 11 | 12 | AuroraAssetEditor 13 | AuroraAssetEditor 14 | AuroraAssetEditor 15 | Copyright 2015-2023 16 | https://github.com/XboxUnity/AuroraAssetEditor 17 | v 18 | $(VersionPrefix)1.4.0.0 19 | 1.4.0.0 20 | 1.4.0.0 21 | 1.4.0.0 22 | 1.4.0.0 23 | Resources\icon.ico 24 | ..\bin\ 25 | 26 | 27 | 28 | True 29 | 30 | 31 | True 32 | 33 | 34 | True 35 | 36 | 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | PreserveNewest 69 | 70 | 71 | PreserveNewest 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/AuroraAsset.cs: -------------------------------------------------------------------------------- 1 | // 2 | // AuroraAsset.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 04/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Drawing; 12 | using System.Drawing.Imaging; 13 | using System.Linq; 14 | using System.Runtime.InteropServices; 15 | using System.Text; 16 | using PhoenixTools; 17 | 18 | public static class AuroraAsset { 19 | public enum AssetType { 20 | Icon, // Icon 21 | Banner, // Banner 22 | Boxart, // Cover 23 | Slot, // NXEArt, currently not used 24 | Background, // Background 25 | ScreenshotStart, // Screenshot 1 26 | ScreenshotEnd = ScreenshotStart + ScreenShotMax, // Screenshot 20 27 | Max = ScreenshotEnd // End of it all 28 | } 29 | 30 | private const int ScreenShotMax = 20; 31 | 32 | private static uint Swap(uint x) { return (x & 0x000000FF) << 24 | (x & 0x0000FF00) << 8 | (x & 0x00FF0000) >> 8 | (x & 0xFF000000) >> 24; } 33 | 34 | private static Image RawArgbToImage(byte[] raw, int width, int height) { 35 | var ret = new Bitmap(width, height); 36 | var rect = new Rectangle(new Point(0, 0), new Size(width, height)); 37 | var bmpData = ret.LockBits(rect, ImageLockMode.ReadWrite, ret.PixelFormat); 38 | Marshal.Copy(raw, 0, bmpData.Scan0, raw.Length); 39 | ret.UnlockBits(bmpData); 40 | return ret; 41 | } 42 | 43 | private static byte[] ImageToRawArgb(Image img) { 44 | var bmp = new Bitmap(img); 45 | var ret = new byte[bmp.Height * bmp.Width * 4]; 46 | var i = 0; 47 | for(var y = 0; y < bmp.Height; y++) { 48 | for(var x = 0; x < bmp.Width; x++) { 49 | var c = bmp.GetPixel(x, y); 50 | ret[i] = c.A; 51 | ret[i + 1] = c.R; 52 | ret[i + 2] = c.G; 53 | ret[i + 3] = c.B; 54 | i += 4; 55 | } 56 | } 57 | return ret; 58 | } 59 | 60 | public class AssetFile { 61 | public readonly int DataOffset; 62 | public readonly AssetPackEntryTable EntryTable; 63 | public readonly AssetPackHeader Header; 64 | 65 | public AssetFile() { 66 | Header = new AssetPackHeader(0x52584541, 1, 0); 67 | EntryTable = new AssetPackEntryTable(); 68 | DataOffset = 20 + (EntryTable.Entries.Length * 64); 69 | DataOffset += 2048 - (DataOffset % 2048); 70 | } 71 | 72 | public AssetFile(byte[] data) { 73 | if(data == null) { 74 | Header = new AssetPackHeader(0x52584541, 1, 0); 75 | EntryTable = new AssetPackEntryTable(); 76 | DataOffset = 20 + (EntryTable.Entries.Length * 64); 77 | DataOffset += 2048 - (DataOffset % 2048); 78 | return; 79 | } 80 | if(data.Length < 2048) 81 | throw new Exception("Invalid asset file size!"); 82 | var magic = Swap(BitConverter.ToUInt32(data, 0)); 83 | if(magic != 0x52584541) 84 | throw new Exception("Invalid asset file magic!"); 85 | var version = Swap(BitConverter.ToUInt32(data, 4)); 86 | if(version != 1) 87 | throw new NotSupportedException("Unsupported asset file version!"); 88 | var datasize = Swap(BitConverter.ToUInt32(data, 8)); 89 | Header = new AssetPackHeader(magic, version, datasize); 90 | EntryTable = new AssetPackEntryTable(data, 12); 91 | DataOffset = 20 + (EntryTable.Entries.Length * 64); 92 | DataOffset += 2048 - (DataOffset % 2048); 93 | var offset = DataOffset; 94 | for(var i = 0; i < EntryTable.Entries.Length; i++) { 95 | if(EntryTable.Entries[i].Size <= 0) 96 | continue; 97 | var tmp = new byte[EntryTable.Entries[i].Size]; 98 | Buffer.BlockCopy(data, offset, tmp, 0, tmp.Length); 99 | SetImage(tmp, i); 100 | offset += tmp.Length; 101 | } 102 | } 103 | 104 | public int PaddingSize { get { return 0x800 - ((0x14 + EntryTable.Entries.Length * 0x40) % 0x800); } } 105 | 106 | public IEnumerable Padding { get { return new byte[PaddingSize]; } } 107 | 108 | public byte[] FileData { 109 | get { 110 | var ret = new List(); 111 | uint offset = 0; 112 | Header.DataSize = 0; 113 | EntryTable.Flags = 0; 114 | EntryTable.ScreenshotCount = 0; 115 | for(var i = 0; i < EntryTable.Entries.Length; i++) { 116 | var entry = EntryTable.Entries[i]; 117 | if(entry.Size <= 0) 118 | continue; 119 | entry.Offset = offset; 120 | offset += entry.Size; 121 | Header.DataSize += entry.Size; 122 | EntryTable.Flags |= (uint)(1 << i); 123 | if(i <= (int)AssetType.ScreenshotEnd && i >= (int)AssetType.ScreenshotStart) 124 | EntryTable.ScreenshotCount++; 125 | } 126 | ret.AddRange(BitConverter.GetBytes(Swap(Header.Magic))); 127 | ret.AddRange(BitConverter.GetBytes(Swap(Header.Version))); 128 | ret.AddRange(BitConverter.GetBytes(Swap(Header.DataSize))); 129 | ret.AddRange(BitConverter.GetBytes(Swap(EntryTable.Flags))); 130 | ret.AddRange(BitConverter.GetBytes(Swap(EntryTable.ScreenshotCount))); 131 | foreach(var entry in EntryTable.Entries) { 132 | ret.AddRange(BitConverter.GetBytes(Swap(entry.Offset))); 133 | ret.AddRange(BitConverter.GetBytes(Swap(entry.Size))); 134 | ret.AddRange(BitConverter.GetBytes(Swap(entry.ExtendedInfo))); 135 | ret.AddRange(entry.TextureHeader); 136 | } 137 | ret.AddRange(Padding); 138 | foreach(var entry in EntryTable.Entries.Where(entry => entry.Size > 0)) 139 | ret.AddRange(entry.VideoData); 140 | return ret.ToArray(); 141 | } 142 | } 143 | 144 | public bool HasBoxArt { get { return EntryTable.Entries[(int)AssetType.Boxart].Size > 0; } } 145 | 146 | public bool HasBackground { get { return EntryTable.Entries[(int)AssetType.Background].Size > 0; } } 147 | 148 | public bool HasScreenshots { get { return EntryTable.ScreenshotCount > 0; } } 149 | 150 | public bool HasIconBanner { get { return EntryTable.Entries[(int)AssetType.Icon].Size > 0 || EntryTable.Entries[(int)AssetType.Banner].Size > 0; } } 151 | 152 | private bool SetImage(Image img, int index, bool useCompression) { 153 | if(index > (int)AssetType.Max) 154 | return false; 155 | if(img == null) { 156 | EntryTable.Entries[index].ImageData = null; 157 | EntryTable.Entries[index].VideoData = new byte[0]; 158 | EntryTable.Entries[index].TextureHeader = new byte[EntryTable.Entries[index].TextureHeader.Length]; 159 | return true; 160 | } 161 | EntryTable.Entries[index].ImageData = img; 162 | var data = ImageToRawArgb(img); 163 | byte[] video = new byte[0], header = new byte[0]; 164 | if(!AuroraAssetDll.ProcessImageToAsset(ref data, img.Width, img.Height, useCompression, ref header, ref video)) 165 | return false; 166 | EntryTable.Entries[index].VideoData = video; 167 | EntryTable.Entries[index].TextureHeader = header; 168 | return true; 169 | } 170 | 171 | private void SetImage(byte[] videoData, int index) { 172 | var imageData = new byte[0]; 173 | int imageWidth, imageHeight; 174 | if(!AuroraAssetDll.ProcessAssetToImage(ref EntryTable.Entries[index].TextureHeader, ref videoData, ref imageData, out imageWidth, out imageHeight)) 175 | return; 176 | EntryTable.Entries[index].VideoData = videoData; 177 | EntryTable.Entries[index].ImageData = RawArgbToImage(imageData, imageWidth, imageHeight); 178 | } 179 | 180 | private void SetImage(AssetFile asset, int index) { 181 | var target = EntryTable.Entries[index]; 182 | var src = asset.EntryTable.Entries[index]; 183 | target.TextureHeader = src.TextureHeader; 184 | target.VideoData = src.VideoData; 185 | target.ImageData = src.ImageData; 186 | } 187 | 188 | public bool SetIcon(Image img, bool useCompression) { return SetImage(img, (int)AssetType.Icon, useCompression); } 189 | 190 | public bool SetBackground(Image img, bool useCompression) { return SetImage(img, (int)AssetType.Background, useCompression); } 191 | 192 | public bool SetBanner(Image img, bool useCompression) { return SetImage(img, (int)AssetType.Banner, useCompression); } 193 | 194 | public bool SetBoxart(Image img, bool useCompression) { return SetImage(img, (int)AssetType.Boxart, useCompression); } 195 | 196 | public bool SetScreenshot(Image img, int num, bool useCompression) { 197 | num += (int)AssetType.ScreenshotStart - 1; 198 | return num <= (int)AssetType.ScreenshotEnd && SetImage(img, num, useCompression); 199 | } 200 | 201 | public Image GetIcon() { return EntryTable.Entries[(int)AssetType.Icon].Size > 0 ? EntryTable.Entries[(int)AssetType.Icon].ImageData : null; } 202 | 203 | public Image GetBoxart() { return EntryTable.Entries[(int)AssetType.Boxart].Size > 0 ? EntryTable.Entries[(int)AssetType.Boxart].ImageData : null; } 204 | 205 | public Image GetBanner() { return EntryTable.Entries[(int)AssetType.Banner].Size > 0 ? EntryTable.Entries[(int)AssetType.Banner].ImageData : null; } 206 | 207 | public Image GetBackground() { return EntryTable.Entries[(int)AssetType.Background].Size > 0 ? EntryTable.Entries[(int)AssetType.Background].ImageData : null; } 208 | 209 | public Image GetScreenshot(int num) { 210 | num += (int)AssetType.ScreenshotStart - 1; 211 | if(num > (int)AssetType.ScreenshotEnd) 212 | return null; 213 | return EntryTable.Entries[num].Size > 0 ? EntryTable.Entries[num].ImageData : null; 214 | } 215 | 216 | public Image[] GetScreenshots() { 217 | var ret = new List(); 218 | for(var i = 0; i < ScreenShotMax; i++) 219 | ret.Add(GetScreenshot(i + 1)); 220 | return ret.ToArray(); 221 | } 222 | 223 | public void SetBoxart(AssetFile asset) { SetImage(asset, (int)AssetType.Boxart); } 224 | 225 | public void SetBackground(AssetFile asset) { SetImage(asset, (int)AssetType.Background); } 226 | 227 | public void SetIcon(AssetFile asset) { SetImage(asset, (int)AssetType.Icon); } 228 | 229 | public void SetBanner(AssetFile asset) { SetImage(asset, (int)AssetType.Banner); } 230 | 231 | public void SetScreenshots(AssetFile asset) { 232 | for(var i = (int)AssetType.ScreenshotStart; i < (int)AssetType.ScreenshotEnd; i++) 233 | SetImage(asset, i); 234 | } 235 | } 236 | 237 | public class AssetPackEntry { 238 | public Image ImageData; 239 | public byte[] TextureHeader; 240 | public byte[] VideoData; 241 | 242 | public AssetPackEntry() { 243 | Offset = 0; 244 | VideoData = new byte[0]; 245 | TextureHeader = new byte[52]; 246 | } 247 | 248 | public AssetPackEntry(byte[] data, int offset) { 249 | Offset = Swap(BitConverter.ToUInt32(data, offset)); 250 | VideoData = new byte[Swap(BitConverter.ToUInt32(data, offset + 4))]; 251 | TextureHeader = new byte[52]; 252 | Buffer.BlockCopy(data, (offset + 12), TextureHeader, 0, TextureHeader.Length); 253 | } 254 | 255 | public uint Offset { get; internal set; } 256 | 257 | public uint Size { get { return (uint)VideoData.Length; } } 258 | 259 | public uint ExtendedInfo { get { return 0; } } 260 | 261 | public Size ImageSize { get { return ImageData.Size; } } 262 | 263 | public override string ToString() { 264 | var sz = ImageSize; 265 | return string.Format("Offset: 0x{0:X}{4}Size: 0x{1:X}{4}Extended Info: 0x{2:X}{4}Texture Header Size: 0x{3:X}{4}Width: {5}{4}Height: {6}", Offset, Size, ExtendedInfo, 266 | TextureHeader.Length, Environment.NewLine, sz.Width, sz.Height); 267 | } 268 | } 269 | 270 | public class AssetPackEntryTable { 271 | public readonly AssetPackEntry[] Entries = new AssetPackEntry[(int)AssetType.Max]; 272 | 273 | public AssetPackEntryTable() { 274 | Flags = 0; 275 | ScreenshotCount = 0; 276 | for(var i = 0; i < Entries.Length; i++) 277 | Entries[i] = new AssetPackEntry(); 278 | } 279 | 280 | public AssetPackEntryTable(byte[] data, int offset) { 281 | Flags = Swap(BitConverter.ToUInt32(data, offset)); 282 | ScreenshotCount = Swap(BitConverter.ToUInt32(data, offset + 4)); 283 | offset += 8; 284 | for(var i = 0; i < Entries.Length; i++, offset += 64) 285 | Entries[i] = new AssetPackEntry(data, offset); 286 | } 287 | 288 | public uint Flags { get; internal set; } 289 | 290 | public uint ScreenshotCount { get; internal set; } 291 | 292 | public override string ToString() { 293 | var sb = new StringBuilder(); 294 | sb.AppendFormat("Flags: 0x{0:X}{1}", Flags, Environment.NewLine); 295 | sb.AppendFormat("ScreenshotCount: {0}{1}", ScreenshotCount, Environment.NewLine); 296 | sb.AppendLine("Entries:"); 297 | for(var i = 0; i < Entries.Length; i++) { 298 | if(i < (int)AssetType.ScreenshotStart || i > (int)AssetType.ScreenshotEnd) 299 | sb.AppendLine(((AssetType)i) + ":"); 300 | else 301 | sb.AppendLine(string.Format("ScreenShot {0}:", i - (int)AssetType.ScreenshotStart)); 302 | sb.AppendLine(Entries[i].Size > 0 ? Entries[i].ToString() : "No data..."); 303 | } 304 | return sb.ToString(); 305 | } 306 | } 307 | 308 | public class AssetPackHeader { 309 | public AssetPackHeader(uint magic, uint version, uint dataSize) { 310 | Magic = magic; 311 | Version = version; 312 | DataSize = dataSize; 313 | } 314 | 315 | public uint Magic { get; private set; } 316 | 317 | public uint Version { get; private set; } 318 | 319 | public uint DataSize { get; internal set; } 320 | 321 | public override string ToString() { 322 | return string.Format("Magic: {0}{3}Version: {1}{3}DataSize: {2}", Encoding.ASCII.GetString(BitConverter.GetBytes(Swap(Magic))), Version, DataSize, Environment.NewLine); 323 | } 324 | } 325 | } 326 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/AuroraAssetDll.cs: -------------------------------------------------------------------------------- 1 | /// ************************************************************************************ 2 | /// ** File: AuroraAssetDll.cs 3 | /// ** Author: MaesterRowen (Phoenix) - May, 2015 4 | /// ** Description: Wrapper class for interfacing with the AuroraAsset.dll in C# 5 | /// ************************************************************************************ 6 | 7 | using System; 8 | using System.Runtime.InteropServices; 9 | 10 | namespace PhoenixTools 11 | { 12 | class AuroraAssetDll 13 | { 14 | [DllImport("AuroraAsset.dll", CallingConvention = CallingConvention.Cdecl)] 15 | private static extern int ConvertImageToAsset(IntPtr imageData, int imageDataLen, int imageWidth, int imageHeight, int useCompression, 16 | IntPtr headerData, out int headerDataLen, IntPtr videoData, out int videoDataLen); 17 | 18 | [DllImport("AuroraAsset.dll", CallingConvention = CallingConvention.Cdecl)] 19 | private static extern int ConvertAssetToImage(IntPtr headerData, int headerDataLen, IntPtr videoData, int videoDataLen, IntPtr imageData, out int imageDataLen, 20 | out int imageWidth, out int imageHeight ); 21 | 22 | [DllImport("AuroraAsset.dll", CallingConvention = CallingConvention.Cdecl)] 23 | private static extern int ConvertDDSToImage(IntPtr ddsData, int ddsDataLen, IntPtr imageData, out int imageDataLen, out int imageWidth, out int imageHeight); 24 | 25 | /// 26 | /// Takes raw pixel data in linear ARGB format and outputs Aurora .asset formatted header and video data 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | public static bool ProcessImageToAsset(ref byte[] pixelData, int imageWidth, int imageHeight, bool useCompression, ref byte[] headerData, ref byte[] videoData) 36 | { 37 | IntPtr hd = IntPtr.Zero, vd = IntPtr.Zero, pd = IntPtr.Zero; 38 | try 39 | { 40 | bool status = false; 41 | 42 | // Store our pixel data array size for later use 43 | int pixelDataLen = pixelData.Length; 44 | if (pixelData == null || pixelDataLen == 0) 45 | { 46 | return false; 47 | } 48 | 49 | // Copy the pixel data to an unmanaged memory buffer 50 | pd = Marshal.AllocHGlobal(pixelDataLen); 51 | Marshal.Copy(pixelData, 0, pd, pixelDataLen); 52 | 53 | // Create variables to hold buffer sizes 54 | int headerDataLen; 55 | int videoDataLen; 56 | int result = ConvertImageToAsset(pd, pixelDataLen, imageWidth, imageHeight, useCompression ? 1 : 0, IntPtr.Zero, out headerDataLen, IntPtr.Zero, out videoDataLen); 57 | if (result == 1) 58 | { 59 | // Allocate unmanaged memory for asset data 60 | hd = Marshal.AllocHGlobal(headerDataLen); 61 | vd = Marshal.AllocHGlobal(videoDataLen); 62 | 63 | // Obtain data 64 | result = ConvertImageToAsset(pd, pixelDataLen, imageWidth, imageHeight, useCompression ? 1 : 0, hd, out headerDataLen, vd, out videoDataLen); 65 | if (result == 1) 66 | { 67 | // Copy our header data 68 | headerData = new byte[headerDataLen]; 69 | Marshal.Copy(hd, headerData, 0, headerDataLen); 70 | 71 | // Copy our video data 72 | videoData = new byte[videoDataLen]; 73 | Marshal.Copy(vd, videoData, 0, videoDataLen); 74 | 75 | status = true; 76 | } 77 | } 78 | return status; 79 | } 80 | catch( Exception e) 81 | { 82 | Console.WriteLine(e.Message); 83 | } 84 | finally { 85 | // Clean up unmanaged file data 86 | if (pd != IntPtr.Zero) 87 | Marshal.FreeHGlobal(pd); 88 | if (hd != IntPtr.Zero) 89 | Marshal.FreeHGlobal(hd); 90 | if (vd != IntPtr.Zero) 91 | Marshal.FreeHGlobal(vd); 92 | } 93 | 94 | return false; 95 | } 96 | 97 | /// 98 | /// Takes asset header and video data and outputs raw pixel data in BGRA format. 99 | /// 100 | /// 101 | /// 102 | /// 103 | /// 104 | /// 105 | /// 106 | public static bool ProcessAssetToImage(ref byte[] headerData, ref byte[] videoData, ref byte[] pixelData, out int imageWidth, out int imageHeight ) 107 | { 108 | IntPtr hd = IntPtr.Zero, vd = IntPtr.Zero, pd = IntPtr.Zero; 109 | try 110 | { 111 | bool status = false; 112 | 113 | int headerDataLen = headerData.Length; 114 | int videoDataLen = videoData.Length; 115 | if (headerDataLen == 0 || videoDataLen == 0) 116 | { 117 | imageWidth = 0; 118 | imageHeight = 0; 119 | return false; 120 | } 121 | 122 | // Copy the pixel data to an unmanaged memory buffer 123 | hd = Marshal.AllocHGlobal(headerDataLen); 124 | Marshal.Copy(headerData, 0, hd, headerDataLen); 125 | 126 | vd = Marshal.AllocHGlobal(videoDataLen); 127 | Marshal.Copy(videoData, 0, vd, videoDataLen); 128 | 129 | // Create variables to hold buffer sizes 130 | int imageDataLen; 131 | int result = ConvertAssetToImage( hd, headerDataLen, vd, videoDataLen, IntPtr.Zero, out imageDataLen, out imageWidth, out imageHeight ); 132 | if (result == 1) 133 | { 134 | // Allocate unmanaged memory for asset data 135 | pd = Marshal.AllocHGlobal(imageDataLen); 136 | 137 | // Obtain data 138 | result = ConvertAssetToImage(hd, headerDataLen, vd, videoDataLen, pd, out imageDataLen, out imageWidth, out imageHeight); 139 | if (result == 1) 140 | { 141 | // Copy our pixel data 142 | pixelData = new byte[imageDataLen]; 143 | Marshal.Copy(pd, pixelData, 0, imageDataLen); 144 | status = true; 145 | } 146 | } 147 | return status; 148 | } 149 | catch (Exception e) 150 | { 151 | Console.WriteLine(e.Message); 152 | } 153 | finally 154 | { 155 | // Clean up unmanaged file data 156 | if (pd != IntPtr.Zero) 157 | Marshal.FreeHGlobal(pd); 158 | if (hd != IntPtr.Zero) 159 | Marshal.FreeHGlobal(hd); 160 | if (vd != IntPtr.Zero) 161 | Marshal.FreeHGlobal(vd); 162 | } 163 | 164 | imageWidth = 0; 165 | imageHeight = 0; 166 | return false; 167 | } 168 | 169 | /// 170 | /// Takes a DDS image data (with header) and outputs raw pixel data in BGRA format. 171 | /// 172 | /// 173 | /// 174 | /// 175 | /// 176 | /// 177 | public static bool ProcessDDSToImage(ref byte[] ddsData, ref byte[] pixelData, out int imageWidth, out int imageHeight) 178 | { 179 | IntPtr dds = IntPtr.Zero, pd = IntPtr.Zero; 180 | try 181 | { 182 | bool status = false; 183 | 184 | int ddsDataLen = ddsData.Length; 185 | if (ddsDataLen == 0) 186 | { 187 | imageWidth = 0; 188 | imageHeight = 0; 189 | return false; 190 | } 191 | 192 | // Copy the pixel data to an unmanaged memory buffer 193 | dds = Marshal.AllocHGlobal(ddsDataLen); 194 | Marshal.Copy(ddsData, 0, dds, ddsDataLen); 195 | 196 | // Create variables to hold buffer sizes 197 | int imageDataLen; 198 | int result = ConvertDDSToImage(dds, ddsDataLen, IntPtr.Zero, out imageDataLen, out imageWidth, out imageHeight); 199 | if (result == 1) 200 | { 201 | // Allocate unmanaged memory for asset data 202 | pd = Marshal.AllocHGlobal(imageDataLen); 203 | 204 | // Obtain data 205 | result = ConvertDDSToImage(dds, ddsDataLen, pd, out imageDataLen, out imageWidth, out imageHeight); 206 | if (result == 1) 207 | { 208 | // Copy our pixel data 209 | pixelData = new byte[imageDataLen]; 210 | Marshal.Copy(pd, pixelData, 0, imageDataLen); 211 | status = true; 212 | } 213 | } 214 | return status; 215 | } 216 | catch (Exception e) 217 | { 218 | Console.WriteLine(e.Message); 219 | } 220 | finally 221 | { 222 | // Clean up unmanaged file data 223 | if (pd != IntPtr.Zero) 224 | Marshal.FreeHGlobal(pd); 225 | if (dds != IntPtr.Zero) 226 | Marshal.FreeHGlobal(dds); 227 | } 228 | 229 | imageWidth = 0; 230 | imageHeight = 0; 231 | return false; 232 | } 233 | } 234 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/AuroraDbManager.cs: -------------------------------------------------------------------------------- 1 | // 2 | // AuroraDbManager.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 14/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Data; 12 | using System.Data.SQLite; 13 | using System.Globalization; 14 | using System.IO; 15 | using System.Linq; 16 | using System.Threading; 17 | 18 | internal static class AuroraDbManager { 19 | private static SQLiteConnection _content; 20 | 21 | private static void ConnectToContent(string path) { 22 | if(_content != null) 23 | _content.Close(); 24 | _content = new SQLiteConnection("Data Source=\"" + path + "\";Version=3;"); 25 | _content.Open(); 26 | } 27 | 28 | private static DataTable GetContentDataTable(string sql) { 29 | var dt = new DataTable(); 30 | try { 31 | var cmd = new SQLiteCommand(sql, _content); 32 | using(var reader = cmd.ExecuteReader()) 33 | dt.Load(reader); 34 | } 35 | catch(Exception ex) { 36 | MainWindow.SaveError(ex); 37 | } 38 | return dt; 39 | } 40 | 41 | public static IEnumerable GetDbTitles(string path) { 42 | ConnectToContent(path); 43 | var ret = GetContentItems().Select(item => item).ToList(); 44 | _content.Close(); 45 | GC.Collect(); 46 | while(true) { 47 | try { 48 | File.Delete(path); 49 | break; 50 | } 51 | catch(IOException) { 52 | Thread.Sleep(100); 53 | } 54 | } 55 | return ret; 56 | } 57 | 58 | private static IEnumerable GetContentItems() { return GetContentDataTable("SELECT * FROM ContentItems").Select().Select(row => new ContentItem(row)).ToArray(); } 59 | 60 | internal class ContentItem { 61 | public ContentItem(DataRow row) { 62 | DatabaseId = ((int)((long)row["Id"])).ToString("X08"); 63 | TitleId = ((int)((long)row["TitleId"])).ToString("X08"); 64 | MediaId = ((int)((long)row["MediaId"])).ToString("X08"); 65 | var discNum = (int)((long)row["DiscNum"]); 66 | if(discNum <= 0) 67 | discNum = 1; 68 | DiscNum = discNum.ToString(CultureInfo.InvariantCulture); 69 | TitleName = (string)row["TitleName"]; 70 | } 71 | 72 | public string TitleId { get; private set; } 73 | 74 | public string MediaId { get; private set; } 75 | 76 | public string DiscNum { get; private set; } 77 | 78 | public string TitleName { get; private set; } 79 | 80 | public string DatabaseId { get; private set; } 81 | 82 | public string Path { get { return string.Format("{0}_{1}", TitleId, DatabaseId); } } 83 | 84 | public void SaveAsBoxart(byte[] data) { App.FtpOperations.SendAssetData(string.Format("GC{0}.asset", TitleId), Path, data); } 85 | 86 | public void SaveAsBackground(byte[] data) { App.FtpOperations.SendAssetData(string.Format("BK{0}.asset", TitleId), Path, data); } 87 | 88 | public void SaveAsIconBanner(byte[] data) { App.FtpOperations.SendAssetData(string.Format("GL{0}.asset", TitleId), Path, data); } 89 | 90 | public void SaveAsScreenshots(byte[] data) { App.FtpOperations.SendAssetData(string.Format("SS{0}.asset", TitleId), Path, data); } 91 | 92 | public byte[] GetBoxart() { return App.FtpOperations.GetAssetData(string.Format("GC{0}.asset", TitleId), Path); } 93 | 94 | public byte[] GetBackground() { return App.FtpOperations.GetAssetData(string.Format("BK{0}.asset", TitleId), Path); } 95 | 96 | public byte[] GetIconBanner() { return App.FtpOperations.GetAssetData(string.Format("GL{0}.asset", TitleId), Path); } 97 | 98 | public byte[] GetScreenshots() { return App.FtpOperations.GetAssetData(string.Format("SS{0}.asset", TitleId), Path); } 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/FSDAsset.cs: -------------------------------------------------------------------------------- 1 | // 2 | // FSDAsset.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Drawing; 11 | using System.Drawing.Imaging; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Runtime.InteropServices; 15 | using PhoenixTools; 16 | 17 | internal class FsdAsset { 18 | public enum FsdAssetType: uint { 19 | Thumbnail = 0x01, 20 | Background = 0x02, 21 | Banner = 0x04, 22 | Boxart = 0x08, 23 | Preview = 0x10, 24 | Screenshot = 0x20, 25 | Slot = 0x40, 26 | FullCover = 0x80 27 | } 28 | 29 | public readonly uint AssetCount; 30 | public readonly uint AssetFlags; 31 | public readonly FsdAssetEntry[] Entries = new FsdAssetEntry[10]; 32 | public readonly uint Magic; 33 | public readonly uint Reserved; 34 | public readonly uint ScreenshotCount; 35 | public readonly FsdScreenshotEntry[] Screenshots = new FsdScreenshotEntry[20]; 36 | public readonly uint Version; 37 | 38 | public FsdAsset(byte[] data) { 39 | if(data.Length < 0x1F8) 40 | throw new Exception("Invalid file size"); 41 | Magic = Swap(BitConverter.ToUInt32(data, 0)); 42 | if(Magic != 0x46534441) 43 | throw new Exception("Invalid asset file magic!"); 44 | Version = Swap(BitConverter.ToUInt32(data, 4)); 45 | if(Version != 1) 46 | throw new NotSupportedException("Unsupported asset file version!"); 47 | Reserved = Swap(BitConverter.ToUInt32(data, 8)); 48 | AssetFlags = Swap(BitConverter.ToUInt32(data, 12)); 49 | AssetCount = Swap(BitConverter.ToUInt32(data, 16)); 50 | ScreenshotCount = Swap(BitConverter.ToUInt32(data, 20)); 51 | for(var i = 0; i < Entries.Length; i++) 52 | Entries[i] = new FsdAssetEntry(ref data, 24 + (i * 16)); 53 | for(var i = 0; i < Screenshots.Length; i++) 54 | Screenshots[i] = new FsdScreenshotEntry(ref data, (24 + (16 * Entries.Length)) + (i * 16)); 55 | } 56 | 57 | private static uint Swap(uint x) { return (x & 0x000000FF) << 24 | (x & 0x0000FF00) << 8 | (x & 0x00FF0000) >> 8 | (x & 0xFF000000) >> 24; } 58 | 59 | private static Image RawArgbToImage(byte[] raw, int width, int height) { 60 | var ret = new Bitmap(width, height); 61 | var rect = new Rectangle(new Point(0, 0), new Size(width, height)); 62 | var bmpData = ret.LockBits(rect, ImageLockMode.ReadWrite, ret.PixelFormat); 63 | Marshal.Copy(raw, 0, bmpData.Scan0, raw.Length); 64 | ret.UnlockBits(bmpData); 65 | return ret; 66 | } 67 | 68 | private static Image GetImage(byte[] data) { 69 | if(data[0] == 'D' || data[1] == 'D' || data[1] == 'S') { 70 | var imageData = new byte[0]; 71 | int imageWidth, imageHeight; 72 | AuroraAssetDll.ProcessDDSToImage(ref data, ref imageData, out imageWidth, out imageHeight); 73 | return RawArgbToImage(imageData, imageWidth, imageHeight); 74 | } 75 | using(var ms = new MemoryStream(data)) { 76 | var img = Image.FromStream(ms); 77 | var img2 = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb); 78 | var g = Graphics.FromImage(img); 79 | g.DrawImage(img2, new Point(0, 0)); 80 | g.Dispose(); 81 | img.Dispose(); 82 | return img2; 83 | } 84 | } 85 | 86 | public Image GetBanner() { return (from entry in Entries where entry.AssetType == FsdAssetType.Banner && entry.Size > 0 select GetImage(entry.Data)).FirstOrDefault(); } 87 | 88 | public Image GetBackground() { return (from entry in Entries where entry.AssetType == FsdAssetType.Background && entry.Size > 0 select GetImage(entry.Data)).FirstOrDefault(); } 89 | 90 | public Image GetIcon() { return (from entry in Entries where entry.AssetType == FsdAssetType.Thumbnail && entry.Size > 0 select GetImage(entry.Data)).FirstOrDefault(); } 91 | 92 | public Image GetBoxart() { return (from entry in Entries where entry.AssetType == FsdAssetType.FullCover && entry.Size > 0 select GetImage(entry.Data)).FirstOrDefault(); } 93 | 94 | public Image[] GetScreenshots() { 95 | var ret = (from entry in Screenshots where entry.Size > 0 select GetImage(entry.Data)).ToList(); 96 | if(ret.Count == 0) 97 | ret.AddRange(from entry in Entries where entry.AssetType == FsdAssetType.Screenshot && entry.Size > 0 select GetImage(entry.Data)); 98 | return ret.ToArray(); 99 | } 100 | 101 | public class FsdAssetEntry { 102 | public readonly FsdAssetType AssetType; 103 | public readonly byte[] Data; 104 | public readonly uint Offset; 105 | public readonly uint Size; 106 | public readonly uint TotalSize; 107 | 108 | public FsdAssetEntry(ref byte[] data, int offset) { 109 | AssetType = (FsdAssetType)Swap(BitConverter.ToUInt32(data, offset)); 110 | Offset = Swap(BitConverter.ToUInt32(data, offset + 4)); 111 | Size = Swap(BitConverter.ToUInt32(data, offset + 8)); 112 | TotalSize = Swap(BitConverter.ToUInt32(data, offset + 12)); 113 | if(Size <= 0) 114 | return; 115 | Data = new byte[Size]; 116 | Buffer.BlockCopy(data, (int)Offset, Data, 0, Data.Length); 117 | } 118 | } 119 | 120 | public class FsdScreenshotEntry { 121 | public readonly byte[] Data; 122 | public readonly uint Offset; 123 | public readonly uint Reserved; 124 | public readonly uint Size; 125 | public readonly uint TotalSize; 126 | 127 | public FsdScreenshotEntry(ref byte[] data, int offset) { 128 | Offset = Swap(BitConverter.ToUInt32(data, offset)); 129 | Size = Swap(BitConverter.ToUInt32(data, offset + 4)); 130 | TotalSize = Swap(BitConverter.ToUInt32(data, offset + 8)); 131 | Reserved = Swap(BitConverter.ToUInt32(data, offset + 12)); 132 | if(Size <= 0) 133 | return; 134 | Data = new byte[Size]; 135 | Buffer.BlockCopy(data, (int)Offset, Data, 0, Data.Length); 136 | } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/FTPOperations.cs: -------------------------------------------------------------------------------- 1 | // 2 | // FTPOperations.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Globalization; 11 | using System.IO; 12 | using System.Linq; 13 | using System.Net; 14 | using System.Net.FtpClient; 15 | using System.Runtime.Serialization; 16 | using System.Runtime.Serialization.Json; 17 | 18 | internal class FtpOperations { 19 | private readonly DataContractJsonSerializer _serializer = new DataContractJsonSerializer(typeof(FtpSettings)); 20 | public EventHandler StatusChanged; 21 | private FtpClient _client; 22 | private FtpSettings _settings; 23 | 24 | public FtpOperations() { LoadSettings(); } 25 | 26 | public string IpAddress { get { return _settings.IpAddress; } } 27 | 28 | public string Username { get { return _settings.Username; } } 29 | 30 | public string Password { get { return _settings.Password; } } 31 | 32 | public bool HaveSettings { get { return _settings.Loaded; } } 33 | 34 | public bool ConnectionEstablished { 35 | get { 36 | if(_client != null && _client.IsConnected) 37 | return _client.IsConnected; 38 | try { MakeConnection(); } 39 | catch {} 40 | return _client != null && _client.IsConnected; 41 | } 42 | } 43 | 44 | public string Port { get { return _settings.Port; } } 45 | 46 | private void SendStatusChanged(string msg, params object[] param) { 47 | var handler = StatusChanged; 48 | if(handler != null) 49 | handler.Invoke(this, new StatusArgs(string.Format(msg, param))); 50 | } 51 | 52 | private void LoadSettings() { 53 | var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 54 | try { 55 | path = !string.IsNullOrWhiteSpace(path) ? Path.Combine(path, "AuroraAssetEditor", "ftp.json") : "ftp.json"; 56 | using(var stream = File.OpenRead(path)) 57 | _settings = (FtpSettings)_serializer.ReadObject(stream); 58 | _settings.Loaded = true; 59 | } 60 | catch { 61 | _settings = new FtpSettings { 62 | Loaded = false 63 | }; 64 | } 65 | } 66 | 67 | public bool TestConnection(string ip, string user, string pass, string port) { 68 | _settings.IpAddress = ip; 69 | _settings.Username = user; 70 | _settings.Password = pass; 71 | _settings.Port = port; 72 | _settings.Loaded = true; 73 | try { 74 | if(MakeConnection()) 75 | return true; 76 | SendStatusChanged("Connection test Failed..."); 77 | return false; 78 | } 79 | catch(Exception ex) { 80 | SendStatusChanged("Error: {0}", ex.Message); 81 | return false; 82 | } 83 | } 84 | 85 | private bool MakeConnection() { 86 | _client = new FtpClient { 87 | Credentials = new NetworkCredential(_settings.Username, _settings.Password), 88 | Host = _settings.IpAddress, 89 | SocketKeepAlive = true 90 | }; 91 | int port; 92 | if(!int.TryParse(_settings.Port, out port)) { 93 | port = 21; 94 | _settings.Port = port.ToString(CultureInfo.InvariantCulture); 95 | } 96 | _client.Port = port; 97 | SendStatusChanged("Connecting to {0}...", _settings.IpAddress); 98 | _client.Connect(); 99 | if(!_client.IsConnected) 100 | return false; 101 | SendStatusChanged("Connection to {0} Established checking for Aurora...", _settings.IpAddress); 102 | var reply = _client.Execute("SITE REVISION"); 103 | if(!reply.Success) 104 | return false; 105 | SendStatusChanged("Connection to Aurora revision {0} Established...", reply.Message); 106 | return true; 107 | } 108 | 109 | public void SaveSettings() { 110 | var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 111 | path = !string.IsNullOrWhiteSpace(path) ? Path.Combine(path, "AuroraAssetEditor", "ftp.json") : "ftp.json"; 112 | path = Path.GetFullPath(path); 113 | if (File.Exists(path)) 114 | File.Delete(path); 115 | var dir = Path.GetDirectoryName(path); 116 | if(string.IsNullOrWhiteSpace(dir)) 117 | return; 118 | if(!Directory.Exists(dir)) 119 | Directory.CreateDirectory(dir); 120 | using(var stream = File.OpenWrite(path)) 121 | _serializer.WriteObject(stream, _settings); 122 | } 123 | 124 | public void SaveSettings(string ip, string user, string pass, string port) { 125 | _settings.IpAddress = ip; 126 | _settings.Username = user; 127 | _settings.Password = pass; 128 | _settings.Port = port; 129 | _settings.Loaded = true; 130 | SaveSettings(); 131 | } 132 | 133 | public bool NavigateToGameDataDir() { 134 | if(_client == null || !_client.IsConnected) { 135 | if(!MakeConnection()) { 136 | SendStatusChanged("Connection failed to {0}", _settings.IpAddress); 137 | return false; // Not connected 138 | } 139 | } 140 | if(_client == null) 141 | return false; 142 | const string dir = "/Game/Data/GameData/"; 143 | SendStatusChanged("Changing working directory to {0}...", dir); 144 | _client.SetWorkingDirectory(dir); 145 | return _client.GetWorkingDirectory().Equals(dir, StringComparison.InvariantCultureIgnoreCase); 146 | } 147 | 148 | public bool NavigateToAssetDir(string assetName) { 149 | if(!NavigateToGameDataDir()) 150 | return false; 151 | var dir = "/Game/Data/GameData/" + assetName + "/"; 152 | SendStatusChanged("Changing working directory to {0}...", dir); 153 | _client.SetWorkingDirectory(dir); 154 | return _client.GetWorkingDirectory().Equals(dir, StringComparison.InvariantCultureIgnoreCase); 155 | } 156 | 157 | public string[] GetDirList() { return (from item in _client.GetListing() where item.Type == FtpFileSystemObjectType.Directory select item.Name).ToArray(); } 158 | 159 | public byte[] GetAssetData(string file, string assetDir) { 160 | if(!NavigateToAssetDir(assetDir)) 161 | return null; 162 | var size = (from item in _client.GetListing() where item.Name.Equals(file, StringComparison.InvariantCultureIgnoreCase) select (int)item.Size).FirstOrDefault(); 163 | if(size <= 0) 164 | return null; 165 | var data = new byte[size]; 166 | var offset = 0; 167 | using(var stream = _client.OpenRead(file)) { 168 | while(offset < data.Length) 169 | offset += stream.Read(data, offset, data.Length - offset); 170 | } 171 | return data; 172 | } 173 | 174 | public bool SendAssetData(string file, string assetDir, byte[] data) { 175 | if(!NavigateToAssetDir(assetDir)) 176 | return false; 177 | using(var stream = _client.OpenWrite(file)) 178 | stream.Write(data, 0, data.Length); 179 | return true; 180 | } 181 | 182 | public bool DownloadContentDb(string path) { 183 | if(_client == null || !_client.IsConnected) { 184 | if(!MakeConnection()) { 185 | SendStatusChanged("Connection failed to {0}", _settings.IpAddress); 186 | return false; // Not connected 187 | } 188 | } 189 | if(_client == null) 190 | return false; 191 | const string dir = "/Game/Data/DataBases/"; 192 | SendStatusChanged("Changing working directory to {0}...", dir); 193 | _client.SetWorkingDirectory(dir); 194 | if(!_client.GetWorkingDirectory().Equals(dir, StringComparison.InvariantCultureIgnoreCase)) 195 | return false; 196 | var size = (from item in _client.GetListing() where item.Name.Equals("Content.db", StringComparison.InvariantCultureIgnoreCase) select (int)item.Size).FirstOrDefault(); 197 | if(size <= 0) 198 | return false; 199 | var data = new byte[size]; 200 | var offset = 0; 201 | using(var stream = _client.OpenRead("Content.db")) { 202 | while(offset < data.Length) 203 | offset += stream.Read(data, offset, data.Length - offset); 204 | } 205 | File.WriteAllBytes(path, data); 206 | return true; 207 | } 208 | 209 | [DataContract] private class FtpSettings { 210 | public bool Loaded; 211 | 212 | [DataMember(Name = "ip")] public string IpAddress { get; set; } 213 | 214 | [DataMember(Name = "user")] public string Username { get; set; } 215 | 216 | [DataMember(Name = "pass")] public string Password { get; set; } 217 | 218 | [DataMember(Name = "port")] public string Port { get; set; } 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/InternetArchiveAssetDownloader.cs: -------------------------------------------------------------------------------- 1 | // 2 | // InternetArchiveDownloader.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by aenrione 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes 9 | { 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Drawing; 13 | using System.Text.RegularExpressions; 14 | using System.IO; 15 | using System.Net; 16 | using System.Text; 17 | 18 | internal class InternetArchiveDownloader 19 | { 20 | private const string BaseUrl = "https://archive.org/download/xboxunity-covers-fulldump_202311/xboxunity-covers-fulldump/"; 21 | public static EventHandler StatusChanged; 22 | 23 | internal static void SendStatusChanged(string msg) 24 | { 25 | var handler = StatusChanged; 26 | if (handler != null) 27 | handler.Invoke(null, new StatusArgs(msg)); 28 | } 29 | 30 | public InternetArchiveAsset[] GetTitleInfo(uint titleId) 31 | { 32 | string titleFolder = string.Format("{0:X08}", titleId); 33 | List assets = new List(); 34 | 35 | try 36 | { 37 | using (WebClient client = new WebClient()) 38 | { 39 | string folderUrl = $"{BaseUrl}{titleFolder}/"; 40 | string htmlContent = client.DownloadString(folderUrl); 41 | 42 | foreach (string subDir in ParseDirectoriesFromHtmlRegex(htmlContent)) 43 | { 44 | assets.Add(new InternetArchiveAsset 45 | { 46 | TitleId = titleId, 47 | MainFolder = titleFolder, 48 | SubFolder = subDir, 49 | AssetType = "Cover" 50 | }); 51 | } 52 | } 53 | } 54 | catch (Exception ex) 55 | { 56 | SendStatusChanged($"Error fetching directory: {ex.Message}"); 57 | } 58 | 59 | return assets.ToArray(); 60 | } 61 | 62 | private IEnumerable ParseDirectoriesFromHtmlRegex(string html) 63 | { 64 | const string HREF_REGEX = "(.+)/"; 65 | 66 | foreach (Match match in Regex.Matches(html, HREF_REGEX)) 67 | { 68 | var hrefValue = match.Groups[1].Value; 69 | var text = match.Groups[2].Value; 70 | 71 | if (hrefValue == text) 72 | { 73 | yield return hrefValue; 74 | } 75 | } 76 | } 77 | 78 | public Image DownloadCover(InternetArchiveAsset asset) 79 | { 80 | try 81 | { 82 | string coverUrl = $"{BaseUrl}{asset.MainFolder}/{asset.SubFolder}/boxart.png"; 83 | using (WebClient wc = new WebClient()) 84 | { 85 | byte[] imageData = wc.DownloadData(coverUrl); 86 | 87 | if (imageData == null || imageData.Length == 0) 88 | { 89 | SendStatusChanged("No image data received"); 90 | return null; 91 | } 92 | 93 | MemoryStream ms = new MemoryStream(imageData); 94 | 95 | try 96 | { 97 | using (Image originalImage = Image.FromStream(ms, true, true)) 98 | { 99 | return new Bitmap(originalImage); 100 | } 101 | } 102 | finally 103 | { 104 | ms.Dispose(); 105 | } 106 | } 107 | } 108 | catch (WebException webEx) 109 | { 110 | SendStatusChanged($"Network error downloading cover: {webEx.Message}"); 111 | return null; 112 | } 113 | catch (ArgumentException argEx) 114 | { 115 | SendStatusChanged($"Invalid image data received: {argEx.Message}"); 116 | return null; 117 | } 118 | catch (Exception ex) 119 | { 120 | SendStatusChanged($"Error downloading cover: {ex.Message}"); 121 | return null; 122 | } 123 | } 124 | } 125 | 126 | // Modified asset class to handle the nested structure 127 | public class InternetArchiveAsset 128 | { 129 | private Image _cover; 130 | public uint TitleId { get; set; } 131 | public string MainFolder { get; set; } // The title ID folder 132 | public string SubFolder { get; set; } // The subfolder containing the actual cover 133 | public string AssetType { get; set; } 134 | public bool HaveAsset { get { return _cover != null; } } 135 | 136 | public Image GetCover() 137 | { 138 | if (_cover == null) 139 | { 140 | var downloader = new InternetArchiveDownloader(); 141 | _cover = downloader.DownloadCover(this); 142 | } 143 | return _cover; 144 | } 145 | 146 | public override string ToString() 147 | { 148 | return $"TitleID: {TitleId:X8} - Variant: {SubFolder}"; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/StatusArgs.cs: -------------------------------------------------------------------------------- 1 | // 2 | // StatusArgs.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | 11 | internal class StatusArgs: EventArgs { 12 | public readonly string StatusMessage; 13 | 14 | public StatusArgs(string statusMessage) { StatusMessage = statusMessage; } 15 | } 16 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/ThreadSafeObservableCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ThreadSafeObservableCollection.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 14/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System.Collections.ObjectModel; 10 | using System.Threading; 11 | using System.Windows.Threading; 12 | 13 | public class ThreadSafeObservableCollection : ObservableCollection { 14 | private readonly Dispatcher _dispatcher; 15 | private readonly ReaderWriterLockSlim _lock; 16 | 17 | public ThreadSafeObservableCollection() { 18 | _dispatcher = Dispatcher.CurrentDispatcher; 19 | _lock = new ReaderWriterLockSlim(); 20 | } 21 | 22 | protected override void ClearItems() { 23 | _dispatcher.InvokeIfRequired(() => { 24 | _lock.EnterWriteLock(); 25 | try { base.ClearItems(); } 26 | finally { _lock.ExitWriteLock(); } 27 | }, DispatcherPriority.DataBind); 28 | } 29 | 30 | protected override void InsertItem(int index, T item) { 31 | _dispatcher.InvokeIfRequired(() => { 32 | if(index > Count) 33 | return; 34 | 35 | _lock.EnterWriteLock(); 36 | try { base.InsertItem(index, item); } 37 | finally { _lock.ExitWriteLock(); } 38 | }, DispatcherPriority.DataBind); 39 | } 40 | 41 | protected override void MoveItem(int oldIndex, int newIndex) { 42 | _dispatcher.InvokeIfRequired(() => { 43 | _lock.EnterReadLock(); 44 | var itemCount = Count; 45 | _lock.ExitReadLock(); 46 | 47 | if(oldIndex >= itemCount | newIndex >= itemCount | oldIndex == newIndex) 48 | return; 49 | 50 | _lock.EnterWriteLock(); 51 | try { base.MoveItem(oldIndex, newIndex); } 52 | finally { _lock.ExitWriteLock(); } 53 | }, DispatcherPriority.DataBind); 54 | } 55 | 56 | protected override void RemoveItem(int index) { 57 | _dispatcher.InvokeIfRequired(() => { 58 | if(index >= Count) 59 | return; 60 | 61 | _lock.EnterWriteLock(); 62 | try { base.RemoveItem(index); } 63 | finally { _lock.ExitWriteLock(); } 64 | }, DispatcherPriority.DataBind); 65 | } 66 | 67 | protected override void SetItem(int index, T item) { 68 | _dispatcher.InvokeIfRequired(() => { 69 | _lock.EnterWriteLock(); 70 | try { base.SetItem(index, item); } 71 | finally { _lock.ExitWriteLock(); } 72 | }, DispatcherPriority.DataBind); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/WpfControlThreadingExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AuroraAssetEditor.Classes { 2 | using System; 3 | using System.Threading; 4 | using System.Windows.Threading; 5 | 6 | public static class WpfControlThreadingExtensions 7 | { 8 | 9 | public static void InvokeIfRequired(this Dispatcher disp, Action dotIt, DispatcherPriority priority) 10 | { 11 | if (disp.Thread != Thread.CurrentThread) 12 | disp.Invoke(priority, dotIt); 13 | else 14 | dotIt(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/XboxAssetDownloader.cs: -------------------------------------------------------------------------------- 1 | // 2 | // XboxAssetDownloader.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Drawing; 12 | using System.Globalization; 13 | using System.IO; 14 | using System.Linq; 15 | using System.Net; 16 | using System.Runtime.Serialization; 17 | using System.Runtime.Serialization.Json; 18 | using System.Text; 19 | using System.Xml; 20 | 21 | internal class XboxAssetDownloader { 22 | public static EventHandler StatusChanged; 23 | private readonly DataContractJsonSerializer _serializer = new DataContractJsonSerializer(typeof(XboxKeywordResponse)); 24 | 25 | internal static void SendStatusChanged(string msg) { 26 | var handler = StatusChanged; 27 | if(handler != null) 28 | handler.Invoke(null, new StatusArgs(msg)); 29 | } 30 | 31 | public XboxTitleInfo[] GetTitleInfo(uint titleId, XboxLocale locale) { 32 | return new[] { 33 | XboxTitleInfo.FromTitleId(titleId, locale) 34 | }; 35 | } 36 | 37 | public XboxTitleInfo[] GetTitleInfo(string keywords, XboxLocale locale) { 38 | var url = string.Format("http://marketplace.xbox.com/{0}/SiteSearch/xbox/?query={1}&PageSize=5", locale.Locale, WebUtility.UrlEncode(keywords)); 39 | var wc = new WebClient(); 40 | var ret = new List(); 41 | using(var stream = wc.OpenRead(url)) { 42 | if(stream == null) 43 | return ret.ToArray(); 44 | var res = (XboxKeywordResponse)_serializer.ReadObject(stream); 45 | ret.AddRange(from entry in res.Entries where entry.DetailsUrl != null let tid = entry.DetailsUrl.IndexOf("d802", StringComparison.Ordinal) where tid > 0 && entry.DetailsUrl.Length >= tid + 12 select uint.Parse(entry.DetailsUrl.Substring(tid + 4, 8), NumberStyles.HexNumber) into titleId select XboxTitleInfo.FromTitleId(titleId, locale)); 46 | } 47 | return ret.ToArray(); 48 | } 49 | 50 | public static XboxLocale[] GetLocales() { 51 | try { 52 | var ret = new List(); 53 | ret.Add(new XboxLocale("es-AR", "Argentina - Espa\xf1ol")); 54 | ret.Add(new XboxLocale("pt-BR", "Brasil - Portugu\xeas")); 55 | ret.Add(new XboxLocale("en-CA", "Canada - English")); 56 | ret.Add(new XboxLocale("fr-CA", "Canada - Fran\xe7ais")); 57 | ret.Add(new XboxLocale("es-CL", "Chile - Espa\xf1ol")); 58 | ret.Add(new XboxLocale("es-CO", "Colombia - Espa\xf1ol")); 59 | ret.Add(new XboxLocale("es-MX", "M\xe9xico - Espa\xf1ol")); 60 | ret.Add(new XboxLocale("en-US", "United States - English")); 61 | ret.Add(new XboxLocale("nl-BE", "Belgi\xeb - Nederlands")); 62 | ret.Add(new XboxLocale("fr-BE", "Belgique - Fran\xe7ais")); 63 | ret.Add(new XboxLocale("cs-CZ", "\u010cesk\xe1 Republika - \u010ce\u0161tina")); 64 | ret.Add(new XboxLocale("da-DK", "Danmark - Dansk")); 65 | ret.Add(new XboxLocale("de-DE", "Deutschland - Deutsch")); 66 | ret.Add(new XboxLocale("es-ES", "Espa\xf1a - Espa\xf1ol")); 67 | ret.Add(new XboxLocale("fr-FR", "France - Fran\xe7ais")); 68 | ret.Add(new XboxLocale("en-IE", "Ireland - English")); 69 | ret.Add(new XboxLocale("it-IT", "Italia - Italiano")); 70 | ret.Add(new XboxLocale("hu-HU", "Magyarorsz\xe1g - Magyar")); 71 | ret.Add(new XboxLocale("nl-NL", "Nederland - Nederlands")); 72 | ret.Add(new XboxLocale("nb-NO", "Norge - Norsk bokm\xe5l")); 73 | ret.Add(new XboxLocale("de-AT", "\xd6sterreich - Deutsch")); 74 | ret.Add(new XboxLocale("pl-PL", "Polska - Polski")); 75 | ret.Add(new XboxLocale("pt-PT", "Portugal - Portugu\xeas")); 76 | ret.Add(new XboxLocale("de-CH", "Schweiz - Deutsch")); 77 | ret.Add(new XboxLocale("sk-SK", "Slovensko - Sloven\u010dina")); 78 | ret.Add(new XboxLocale("fr-CH", "Suisse - Fran\xe7ais")); 79 | ret.Add(new XboxLocale("fi-FI", "Suomi - Suomi")); 80 | ret.Add(new XboxLocale("sv-SE", "Sverige - Svenska")); 81 | ret.Add(new XboxLocale("en-GB", "United Kingdom - English")); 82 | ret.Add(new XboxLocale("el-GR", "\u0395\u03bb\u03bb\u03ac\u03b4\u03b1 - \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac")); 83 | ret.Add(new XboxLocale("ru-RU", "\u0420\u043e\u0441\u0441\u0438\u044f - \u0420\u0443\u0441\u0441\u043a\u0438\u0439")); 84 | ret.Add(new XboxLocale("en-AU", "Australia - English")); 85 | ret.Add(new XboxLocale("en-HK", "Hong Kong SAR / Macao SAR - English")); 86 | ret.Add(new XboxLocale("en-IN", "India - English")); 87 | ret.Add(new XboxLocale("id-ID", "Indonesia - Bahasa Indonesia")); 88 | ret.Add(new XboxLocale("en-MY", "Malaysia - English")); 89 | ret.Add(new XboxLocale("en-NZ", "New Zealand - English")); 90 | ret.Add(new XboxLocale("en-PH", "Philippines - English")); 91 | ret.Add(new XboxLocale("en-SG", "Singapore - English")); 92 | ret.Add(new XboxLocale("vi-VN", "Vi\u1ec7t Nam - Ti\xea\u0301ng vi\u1ec7t")); 93 | ret.Add(new XboxLocale("th-TH", "\u0e44\u0e17\u0e22 - \u0e44\u0e17\u0e22")); 94 | ret.Add(new XboxLocale("ko-KR", "\ub300\ud55c\ubbfc\uad6d - \ud55c\uad6d\uc5b4")); 95 | ret.Add(new XboxLocale("zh-CN", "\u4e2d\u56fd - \u4e2d\u6587")); 96 | ret.Add(new XboxLocale("zh-TW", "\u53f0\u7063 - \u7e41\u9ad4\u4e2d\u6587")); 97 | ret.Add(new XboxLocale("ja-JP", "\u65e5\u672c - \u65e5\u672c\u8a9e")); 98 | ret.Add(new XboxLocale("zh-HK", "\u9999\u6e2f\u7279\u5225\u884c\u653f\u5340/\u6fb3\u9580\u7279\u5225\u884c\u653f\u5340 - \u7e41\u9ad4\u4e2d\u6587")); 99 | ret.Add(new XboxLocale("en-ZA", "South Africa - English")); 100 | ret.Add(new XboxLocale("tr-TR", "T\xfcrkiye - T\xfcrk\xe7e")); 101 | ret.Add(new XboxLocale("he-IL", "\u05d9\u05e9\u05e8\u05d0\u05dc - \u05e2\u05d1\u05e8\u05d9\u05ea")); 102 | ret.Add(new XboxLocale("ar-AE", "\u0627\u0644\u0625\u0645\u0627\u0631\u0627\u062a \u0627\u0644\u0639\u0631\u0628\u064a\u0629 \u0627\u0644\u0645\u062a\u062d\u062f\u0629 - \u0627\u0644\u0639\u0631\u0628\u064a\u0629")); 103 | ret.Add(new XboxLocale("ar-SA", "\u0627\u0644\u0645\u0645\u0644\u0643\u0629 \u0627\u0644\u0639\u0631\u0628\u064a\u0629 \u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629 - \u0627\u0644\u0639\u0631\u0628\u064a\u0629")); 104 | ret.Sort((l1, l2) => string.CompareOrdinal(l1.ToString(), l2.ToString())); 105 | return ret.ToArray(); 106 | } 107 | catch { return new XboxLocale[0]; } 108 | } 109 | } 110 | 111 | public class XboxTitleInfo { 112 | public enum XboxAssetType { 113 | Icon, 114 | Banner, 115 | Background, 116 | Screenshot 117 | } 118 | 119 | public string Title { get; private set; } 120 | 121 | public string TitleId { get; private set; } 122 | 123 | public string Locale { get; private set; } 124 | 125 | public XboxAssetInfo[] AssetsInfo { get; private set; } 126 | 127 | public XboxAsset[] Assets { 128 | get { 129 | if(AssetsInfo.Any(info => !info.HaveAsset)) 130 | XboxAssetDownloader.SendStatusChanged(string.Format("Downloading assets for {0}...", Title)); 131 | var ret = AssetsInfo.Select(info => info.GetAsset()).ToArray(); 132 | return ret; 133 | } 134 | } 135 | 136 | public XboxAsset[] IconAssets { 137 | get { 138 | if(AssetsInfo.Where(info => info.AssetType == XboxAssetType.Icon).Any(info => !info.HaveAsset)) 139 | XboxAssetDownloader.SendStatusChanged(string.Format("Downloading icon assets for {0}...", Title)); 140 | var ret = AssetsInfo.Where(info => info.AssetType == XboxAssetType.Icon).Select(info => info.GetAsset()).ToArray(); 141 | return ret; 142 | } 143 | } 144 | 145 | public XboxAsset[] BannerAssets { 146 | get { 147 | if(AssetsInfo.Where(info => info.AssetType == XboxAssetType.Banner).Any(info => !info.HaveAsset)) 148 | XboxAssetDownloader.SendStatusChanged(string.Format("Downloading banner assets for {0}...", Title)); 149 | var ret = AssetsInfo.Where(info => info.AssetType == XboxAssetType.Banner).Select(info => info.GetAsset()).ToArray(); 150 | return ret; 151 | } 152 | } 153 | 154 | public XboxAsset[] BackgroundAssets { 155 | get { 156 | if(AssetsInfo.Where(info => info.AssetType == XboxAssetType.Background).Any(info => !info.HaveAsset)) 157 | XboxAssetDownloader.SendStatusChanged(string.Format("Downloading background assets for {0}...", Title)); 158 | var ret = AssetsInfo.Where(info => info.AssetType == XboxAssetType.Background).Select(info => info.GetAsset()).ToArray(); 159 | return ret; 160 | } 161 | } 162 | 163 | public XboxAsset[] ScreenshotsAssets { 164 | get { 165 | if(AssetsInfo.Where(info => info.AssetType == XboxAssetType.Screenshot).Any(info => !info.HaveAsset)) 166 | XboxAssetDownloader.SendStatusChanged(string.Format("Downloading screenshot assets for {0}...", Title)); 167 | var ret = AssetsInfo.Where(info => info.AssetType == XboxAssetType.Screenshot).Select(info => info.GetAsset()).ToArray(); 168 | return ret; 169 | } 170 | } 171 | 172 | private static void ParseXml(Stream xmlData, XboxTitleInfo titleInfo) { 173 | XboxAssetDownloader.SendStatusChanged("Parsing Title/Asset info..."); 174 | var ret = new List(); 175 | using(var xml = XmlReader.Create(xmlData)) { 176 | while(xml.Read()) { 177 | if(!xml.IsStartElement()) 178 | continue; 179 | if (xml.Name.ToLower() == "live:fulltitle") { 180 | xml.Read(); 181 | titleInfo.Title = xml.Value; 182 | continue; 183 | } 184 | // add every 'live:fileurl' within 'live:slideshows' as a screenshot asset 185 | if (xml.Name.ToLower() == "live:slideshows") { 186 | while (xml.Read()) { 187 | if (!xml.IsStartElement() && xml.Name.ToLower() == "live:slideshows") { 188 | break; 189 | } 190 | if (xml.IsStartElement() && xml.Name.ToLower() == "live:fileurl") { 191 | xml.Read(); 192 | var url = new Uri(xml.Value); 193 | ret.Add(new XboxAssetInfo(url, XboxAssetType.Screenshot, titleInfo)); 194 | } 195 | } 196 | } 197 | // add every 'live:image' within 'live:images' that has both 'live:relationshiptype' and 'live:fileurl' properties as an asset 198 | // the value of 'live:relationshiptype' is used to determine the asset type 199 | if (xml.Name.ToLower() == "live:images") { 200 | var imageRelationshipType = ""; 201 | var imageFileUrl = ""; 202 | while (xml.Read()) { 203 | if (!xml.IsStartElement() && xml.Name.ToLower() == "live:images") { 204 | break; 205 | } 206 | if (!xml.IsStartElement() && xml.Name.ToLower() == "live:image") { 207 | if (imageRelationshipType != "" && imageFileUrl != "") { 208 | switch (imageRelationshipType) { 209 | case "15": 210 | ret.Add(new XboxAssetInfo(new Uri(imageFileUrl), XboxAssetType.Icon, titleInfo)); 211 | break; 212 | case "23": 213 | ret.Add(new XboxAssetInfo(new Uri(imageFileUrl), XboxAssetType.Icon, titleInfo)); 214 | break; 215 | case "25": 216 | ret.Add(new XboxAssetInfo(new Uri(imageFileUrl), XboxAssetType.Background, titleInfo)); 217 | break; 218 | case "27": 219 | ret.Add(new XboxAssetInfo(new Uri(imageFileUrl), XboxAssetType.Banner, titleInfo)); 220 | break; 221 | default: 222 | break; 223 | } 224 | } 225 | imageRelationshipType = ""; 226 | imageFileUrl = ""; 227 | continue; 228 | } 229 | if (xml.IsStartElement() && xml.Name.ToLower() == "live:relationshiptype") { 230 | xml.Read(); 231 | imageRelationshipType = xml.Value; 232 | } 233 | if (xml.IsStartElement() && xml.Name.ToLower() == "live:fileurl") { 234 | xml.Read(); 235 | imageFileUrl = xml.Value; 236 | } 237 | } 238 | } 239 | } 240 | } 241 | titleInfo.AssetsInfo = ret.ToArray(); 242 | XboxAssetDownloader.SendStatusChanged("Finished parsing Title/Asset info..."); 243 | } 244 | 245 | public static XboxTitleInfo FromTitleId(uint titleId, XboxLocale locale) { 246 | var ret = new XboxTitleInfo { 247 | TitleId = string.Format("{0:X08}", titleId), 248 | Locale = locale.ToString() 249 | }; 250 | var wc = new WebClient(); 251 | var url = 252 | string.Format( 253 | "http://catalog-cdn.xboxlive.com/Catalog/Catalog.asmx/Query?methodName=FindGames&Names=Locale&Values={0}&Names=LegalLocale&Values={0}&Names=Store&Values=1&Names=PageSize&Values=100&Names=PageNum&Values=1&Names=DetailView&Values=5&Names=OfferFilterLevel&Values=1&Names=MediaIds&Values=66acd000-77fe-1000-9115-d802{1:X8}&Names=UserTypes&Values=2&Names=MediaTypes&Values=1&Names=MediaTypes&Values=21&Names=MediaTypes&Values=23&Names=MediaTypes&Values=37&Names=MediaTypes&Values=46", 254 | locale.Locale, titleId); 255 | XboxAssetDownloader.SendStatusChanged("Downloading title/asset information..."); 256 | using(var stream = new MemoryStream(wc.DownloadData(url))) 257 | ParseXml(stream, ret); 258 | return ret; 259 | } 260 | 261 | public class XboxAsset { 262 | public readonly XboxAssetType AssetType; 263 | 264 | public readonly Image Image; 265 | 266 | public XboxAsset(Image image, XboxAssetType assetType) { 267 | Image = image; 268 | AssetType = assetType; 269 | } 270 | } 271 | 272 | public class XboxAssetInfo { 273 | public readonly XboxAssetType AssetType; 274 | public readonly Uri AssetUrl; 275 | private readonly XboxTitleInfo _titleInfo; 276 | private XboxAsset _asset; 277 | 278 | public XboxAssetInfo(Uri assetUrl, XboxAssetType assetType, XboxTitleInfo titleInfo) { 279 | AssetUrl = assetUrl; 280 | AssetType = assetType; 281 | _titleInfo = titleInfo; 282 | } 283 | 284 | public bool HaveAsset { get { return _asset != null; } } 285 | 286 | public XboxAsset GetAsset() { 287 | if(_asset != null) 288 | return _asset; // We already have it 289 | var wc = new WebClient(); 290 | var data = wc.DownloadData(AssetUrl); 291 | var ms = new MemoryStream(data); 292 | var img = Image.FromStream(ms); 293 | return _asset = new XboxAsset(img, AssetType); 294 | } 295 | 296 | public override string ToString() { return string.Format("{0} [ {1} ] {2}", _titleInfo.Title, _titleInfo.TitleId, AssetType); } 297 | } 298 | } 299 | 300 | public class XboxLocale { 301 | public readonly string Locale; 302 | 303 | private readonly string _name; 304 | 305 | public XboxLocale(string locale, string name) { 306 | Locale = locale; 307 | _name = name; 308 | } 309 | 310 | public override string ToString() { return string.Format("{0} [ {1} ]", _name, Locale); } 311 | } 312 | 313 | [DataContract] public class XboxKeywordResponse { 314 | [DataMember(Name = "entries")] public Entry[] Entries { get; set; } 315 | 316 | [DataContract] public class Entry { 317 | [DataMember(Name = "detailsUrl")] public string DetailsUrl { get; set; } 318 | //There is more data sent both here and ^, but we only need this, so i only added that... 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Classes/XboxUnity.cs: -------------------------------------------------------------------------------- 1 | // 2 | // XboxUnity.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Classes { 9 | using System; 10 | using System.Drawing; 11 | using System.IO; 12 | using System.Linq; 13 | using System.Net; 14 | using System.Runtime.Serialization; 15 | using System.Runtime.Serialization.Json; 16 | 17 | internal static class XboxUnity { 18 | private static readonly DataContractJsonSerializer Serializer = new DataContractJsonSerializer(typeof(UnityResponse[])); 19 | 20 | private static string GetUnityUrl(string searchTerm) { return string.Format("http://xboxunity.net/api/Covers/{0}", WebUtility.UrlEncode(searchTerm)); } 21 | 22 | public static XboxUnityAsset[] GetUnityCoverInfo(string searchTerm) { 23 | using(var wc = new WebClient()) { 24 | try { 25 | var stream = wc.OpenRead(GetUnityUrl(searchTerm)); 26 | return stream != null ? ((UnityResponse[])Serializer.ReadObject(stream)).Select(t => new XboxUnityAsset(t)).ToArray() : new XboxUnityAsset[0]; 27 | } 28 | catch(Exception ex) { 29 | MainWindow.SaveError(ex); 30 | return new XboxUnityAsset[0]; 31 | } 32 | } 33 | } 34 | 35 | public static string GetHomebrewTitleFromFtp(string path) { 36 | var data = App.FtpOperations.GetAssetData("GameCoverInfo.bin", path); 37 | if(data == null || data.Length < 10) 38 | return "N/A"; 39 | using(var ms = new MemoryStream(data)) { 40 | var response = (UnityResponse[])Serializer.ReadObject(ms); 41 | return response.Length <= 0 ? "N/A" : response[0].Name; 42 | } 43 | } 44 | 45 | [DataContract] internal class UnityResponse { 46 | [DataMember(Name = "titleid")] public string TitleId { get; set; } 47 | 48 | [DataMember(Name = "name")] public string Name { get; set; } 49 | 50 | [DataMember(Name = "official")] public bool Official { get; set; } 51 | 52 | [DataMember(Name = "filesize")] public string FileSize { get; set; } 53 | 54 | [DataMember(Name = "url")] public string Url { get; set; } 55 | 56 | [DataMember(Name = "front")] public string Front { get; set; } 57 | 58 | [DataMember(Name = "thumbnail")] public string Thumbnail { get; set; } 59 | 60 | [DataMember(Name = "author")] public string Author { get; set; } 61 | 62 | [DataMember(Name = "uploaddate")] public string UploadDate { get; set; } 63 | 64 | [DataMember(Name = "rating")] public string Rating { get; set; } 65 | 66 | [DataMember(Name = "link")] public string Link { get; set; } 67 | } 68 | 69 | public class XboxUnityAsset { 70 | private readonly UnityResponse _unityResponse; 71 | private Image _cover; 72 | 73 | public XboxUnityAsset(UnityResponse response) { _unityResponse = response; } 74 | 75 | public bool HaveAsset { get { return _cover != null; } } 76 | 77 | public string Title { get { return _unityResponse.Name; } } 78 | 79 | private static Image GetImage(string url) { 80 | var wc = new WebClient(); 81 | var data = wc.DownloadData(url); 82 | var ms = new MemoryStream(data); 83 | return Image.FromStream(ms); 84 | } 85 | 86 | public Image GetCover() { 87 | if(_cover != null) 88 | return _cover; 89 | return _cover = GetImage(_unityResponse.Url); 90 | } 91 | 92 | public override string ToString() { 93 | return string.Format(_unityResponse.Official ? "Official cover for {0} Rating: {1}" : "Cover for {0} Rating: {1}", _unityResponse.Name, _unityResponse.Rating ?? "N/A"); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/BackgroundControl.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 13 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/BackgroundControl.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BackgroundControl.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Controls { 9 | using System; 10 | using System.ComponentModel; 11 | using System.Drawing.Imaging; 12 | using System.IO; 13 | using System.Windows; 14 | using System.Windows.Controls; 15 | using System.Windows.Media.Imaging; 16 | using Classes; 17 | using Microsoft.Win32; 18 | using Image = System.Drawing.Image; 19 | using Size = System.Drawing.Size; 20 | 21 | /// 22 | /// Interaction logic for BackgroundControl.xaml 23 | /// 24 | public partial class BackgroundControl { 25 | private readonly MainWindow _main; 26 | internal bool HavePreview; 27 | private AuroraAsset.AssetFile _assetFile; 28 | private MemoryStream _memoryStream; 29 | 30 | public BackgroundControl(MainWindow main) { 31 | InitializeComponent(); 32 | _main = main; 33 | _assetFile = new AuroraAsset.AssetFile(); 34 | } 35 | 36 | public void Save() { 37 | var sfd = new SaveFileDialog(); 38 | if(sfd.ShowDialog() == true) 39 | Save(sfd.FileName); 40 | } 41 | 42 | public void Save(string filename) { File.WriteAllBytes(filename, _assetFile.FileData); } 43 | 44 | public void Reset() { 45 | SetPreview(null); 46 | _assetFile = new AuroraAsset.AssetFile(); 47 | } 48 | 49 | public void Load(AuroraAsset.AssetFile asset) { 50 | _assetFile.SetBackground(asset); 51 | Dispatcher.Invoke(new Action(() => SetPreview(_assetFile.GetBackground()))); 52 | } 53 | 54 | private void SetPreview(Image img) { 55 | if(img == null) { 56 | PreviewImg.Source = new BitmapImage(new Uri("pack://application:,,,/Resources/Placeholders/background.png", UriKind.Absolute)); 57 | HavePreview = false; 58 | return; 59 | } 60 | if(_memoryStream != null) 61 | _memoryStream.Close(); 62 | var bi = new BitmapImage(); 63 | _memoryStream = new MemoryStream(); 64 | img.Save(_memoryStream, ImageFormat.Bmp); 65 | _memoryStream.Seek(0, SeekOrigin.Begin); 66 | bi.BeginInit(); 67 | bi.StreamSource = _memoryStream; 68 | bi.EndInit(); 69 | PreviewImg.Source = bi; 70 | HavePreview = true; 71 | } 72 | 73 | public void Load(Image img) { 74 | var shouldUseCompression = false; 75 | Dispatcher.Invoke(new Action(() => shouldUseCompression = _main.UseCompression.IsChecked)); 76 | _assetFile.SetBackground(img, shouldUseCompression); 77 | Dispatcher.Invoke(new Action(() => SetPreview(img))); 78 | } 79 | 80 | private void OnDragEnter(object sender, DragEventArgs e) { _main.OnDragEnter(sender, e); } 81 | 82 | private void OnDrop(object sender, DragEventArgs e) { _main.DragDrop(this, e); } 83 | 84 | internal void SaveImageToFileOnClick(object sender, RoutedEventArgs e) { MainWindow.SaveToFile(_assetFile.GetBackground(), "Select where to save the Background", "background.png"); } 85 | 86 | internal void SelectNewBackground(object sender, RoutedEventArgs e) { 87 | var bw = new BackgroundWorker(); 88 | bw.DoWork += (o, args) => { 89 | var img = _main.LoadImage("Select new background", "background.png", new Size(1280, 720)); 90 | if(img != null) 91 | Load(img); 92 | }; 93 | bw.RunWorkerCompleted += (o, args) => _main.BusyIndicator.Visibility = Visibility.Collapsed; 94 | bw.RunWorkerAsync(); 95 | } 96 | 97 | private void OnContextMenuOpening(object sender, ContextMenuEventArgs e) { SaveContextMenuItem.IsEnabled = HavePreview; } 98 | 99 | public byte[] GetData() { return _assetFile.FileData; } 100 | } 101 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/BoxartControl.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 13 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/BoxartControl.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BoxartControl.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Controls { 9 | using System; 10 | using System.ComponentModel; 11 | using System.Drawing.Imaging; 12 | using System.IO; 13 | using System.Windows; 14 | using System.Windows.Controls; 15 | using System.Windows.Media.Imaging; 16 | using Classes; 17 | using Microsoft.Win32; 18 | using Image = System.Drawing.Image; 19 | using Size = System.Drawing.Size; 20 | 21 | /// 22 | /// Interaction logic for BoxartControl.xaml 23 | /// 24 | public partial class BoxartControl { 25 | private readonly MainWindow _main; 26 | internal bool HavePreview; 27 | private AuroraAsset.AssetFile _assetFile; 28 | private MemoryStream _memoryStream; 29 | 30 | public BoxartControl(MainWindow main) { 31 | InitializeComponent(); 32 | _main = main; 33 | _assetFile = new AuroraAsset.AssetFile(); 34 | } 35 | 36 | public void Save() { 37 | var sfd = new SaveFileDialog(); 38 | if(sfd.ShowDialog() == true) 39 | Save(sfd.FileName); 40 | } 41 | 42 | public void Save(string filename) { File.WriteAllBytes(filename, _assetFile.FileData); } 43 | 44 | public void Reset() { 45 | SetPreview(null); 46 | _assetFile = new AuroraAsset.AssetFile(); 47 | } 48 | 49 | public void Load(AuroraAsset.AssetFile asset) { 50 | _assetFile.SetBoxart(asset); 51 | Dispatcher.Invoke(new Action(() => SetPreview(_assetFile.GetBoxart()))); 52 | } 53 | 54 | private void SetPreview(Image img) { 55 | if(img == null) { 56 | PreviewImg.Source = new BitmapImage(new Uri("pack://application:,,,/Resources/Placeholders/cover.png", UriKind.Absolute)); 57 | HavePreview = false; 58 | return; 59 | } 60 | if(_memoryStream != null) 61 | _memoryStream.Close(); 62 | var bi = new BitmapImage(); 63 | _memoryStream = new MemoryStream(); 64 | img.Save(_memoryStream, ImageFormat.Bmp); 65 | _memoryStream.Seek(0, SeekOrigin.Begin); 66 | bi.BeginInit(); 67 | bi.StreamSource = _memoryStream; 68 | bi.EndInit(); 69 | PreviewImg.Source = bi; 70 | HavePreview = true; 71 | } 72 | 73 | public void Load(Image img) { 74 | var shouldUseCompression = false; 75 | Dispatcher.Invoke(new Action(() => shouldUseCompression = _main.UseCompression.IsChecked)); 76 | _assetFile.SetBoxart(img, shouldUseCompression); 77 | Dispatcher.Invoke(new Action(() => SetPreview(img))); 78 | } 79 | 80 | private void OnDragEnter(object sender, DragEventArgs e) { _main.OnDragEnter(sender, e); } 81 | 82 | private void OnDrop(object sender, DragEventArgs e) { _main.DragDrop(this, e); } 83 | 84 | internal void SaveImageToFileOnClick(object sender, RoutedEventArgs e) { MainWindow.SaveToFile(_assetFile.GetBoxart(), "Select where to save the Cover", "cover.png"); } 85 | 86 | internal void SelectNewCover(object sender, RoutedEventArgs e) { 87 | var bw = new BackgroundWorker(); 88 | bw.DoWork += (o, args) => { 89 | var img = _main.LoadImage("Select new cover", "cover.png", new Size(900, 600)); 90 | if(img != null) 91 | Load(img); 92 | }; 93 | bw.RunWorkerCompleted += (o, args) => _main.BusyIndicator.Visibility = Visibility.Collapsed; 94 | bw.RunWorkerAsync(); 95 | } 96 | 97 | private void OnContextMenuOpening(object sender, ContextMenuEventArgs e) { SaveContextMenuItem.IsEnabled = HavePreview; } 98 | 99 | public byte[] GetData() { return _assetFile.FileData; } 100 | } 101 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/CircularProgressBar.xaml: -------------------------------------------------------------------------------- 1 |  6 | 10 | 15 | 19 | 23 | 27 | 31 | 35 | 39 | 43 | 47 | 51 | 52 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/CircularProgressBar.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CircularProgressBar.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor.Controls { 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Controls; 12 | using System.Windows.Input; 13 | using System.Windows.Threading; 14 | 15 | public partial class CircularProgressBar { 16 | #region Data 17 | 18 | private readonly DispatcherTimer _animationTimer; 19 | 20 | #endregion 21 | 22 | #region Constructor 23 | 24 | public CircularProgressBar() { 25 | InitializeComponent(); 26 | 27 | _animationTimer = new DispatcherTimer(DispatcherPriority.ContextIdle) { 28 | Interval = new TimeSpan(0, 0, 0, 0, 75) 29 | }; 30 | } 31 | 32 | #endregion 33 | 34 | #region Private Methods 35 | 36 | private void Start() { 37 | Mouse.OverrideCursor = Cursors.Wait; 38 | _animationTimer.Tick += HandleAnimationTick; 39 | _animationTimer.Start(); 40 | } 41 | 42 | private void Stop() { 43 | _animationTimer.Stop(); 44 | Mouse.OverrideCursor = Cursors.Arrow; 45 | _animationTimer.Tick -= HandleAnimationTick; 46 | } 47 | 48 | private void HandleAnimationTick(object sender, EventArgs e) { SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360; } 49 | 50 | private void HandleLoaded(object sender, RoutedEventArgs e) { 51 | const double offset = Math.PI; 52 | const double step = Math.PI * 2 / 10.0; 53 | 54 | SetPosition(C0, offset, 0.0, step); 55 | SetPosition(C1, offset, 1.0, step); 56 | SetPosition(C2, offset, 2.0, step); 57 | SetPosition(C3, offset, 3.0, step); 58 | SetPosition(C4, offset, 4.0, step); 59 | SetPosition(C5, offset, 5.0, step); 60 | SetPosition(C6, offset, 6.0, step); 61 | SetPosition(C7, offset, 7.0, step); 62 | SetPosition(C8, offset, 8.0, step); 63 | } 64 | 65 | private static void SetPosition(DependencyObject ellipse, double offset, double posOffSet, double step) { 66 | ellipse.SetValue(Canvas.LeftProperty, 50.0 + Math.Sin(offset + posOffSet * step) * 50.0); 67 | ellipse.SetValue(Canvas.TopProperty, 50 + Math.Cos(offset + posOffSet * step) * 50.0); 68 | } 69 | 70 | private void HandleUnloaded(object sender, RoutedEventArgs e) { Stop(); } 71 | 72 | private void HandleVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { 73 | var isVisible = (bool)e.NewValue; 74 | 75 | if(isVisible) 76 | Start(); 77 | else 78 | Stop(); 79 | } 80 | 81 | #endregion 82 | } 83 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/Controls/FtpAssetsControl.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 35 | 37 | 39 | 41 | 43 | 45 | 47 | 48 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /AuroraAssetEditor/InputDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // InputDialog.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 07/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor { 9 | using System; 10 | using System.Windows; 11 | 12 | public partial class InputDialog { 13 | public InputDialog(Window owner, string information, string defaultValue = "") { 14 | InitializeComponent(); 15 | Icon = App.WpfIcon; 16 | Owner = owner; 17 | InfoLabel.Text = information; 18 | ValueBox.Text = defaultValue; 19 | } 20 | 21 | public string Value { get { return ValueBox.Text; } } 22 | 23 | private void btnDialogOk_Click(object sender, RoutedEventArgs e) { DialogResult = true; } 24 | 25 | private void Window_ContentRendered(object sender, EventArgs e) { 26 | ValueBox.SelectAll(); 27 | ValueBox.Focus(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 51 | 52 | 55 | 58 | 61 | 64 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 77 | 80 | 83 | 84 | 85 | 88 | 89 | 90 | 91 | 96 | 97 | 98 | 99 | 100 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Models/Game.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AuroraAssetEditor.Models 9 | { 10 | public class Game : INotifyPropertyChanged 11 | { 12 | private string _title; 13 | private string _titleId; 14 | private string _dbId; 15 | private bool _isGameSelected; 16 | 17 | public string Title 18 | { 19 | get => _title; 20 | set { _title = value; OnPropertyChanged(Title); } 21 | } 22 | 23 | public string TitleId 24 | { 25 | get => _titleId; 26 | set { _titleId = value; OnPropertyChanged(TitleId); } 27 | } 28 | 29 | public string DbId 30 | { 31 | get => _dbId; 32 | set { _dbId = value; OnPropertyChanged(DbId); } 33 | } 34 | 35 | public bool IsGameSelected 36 | { 37 | get => _isGameSelected; 38 | set { _isGameSelected = value; OnPropertyChanged(nameof(IsGameSelected)); } 39 | } 40 | 41 | public event PropertyChangedEventHandler PropertyChanged; 42 | 43 | protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) 44 | { 45 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/Placeholders/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/Placeholders/background.png -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/Placeholders/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/Placeholders/banner.png -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/Placeholders/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/Placeholders/cover.png -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/Placeholders/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/Placeholders/icon.png -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/Placeholders/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/Placeholders/screenshot.png -------------------------------------------------------------------------------- /AuroraAssetEditor/Resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/Resources/icon.ico -------------------------------------------------------------------------------- /AuroraAssetEditor/TitleAndDbIdDialog.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 23 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AuroraAssetEditor/TitleAndDbIdDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TitleAndDbIdDialog.xaml.cs 3 | // AuroraAssetEditor 4 | // 5 | // Created by Swizzy on 10/05/2015 6 | // Copyright (c) 2015 Swizzy. All rights reserved. 7 | 8 | namespace AuroraAssetEditor { 9 | using System.Globalization; 10 | using System.Text.RegularExpressions; 11 | using System.Windows; 12 | using System.Windows.Controls; 13 | using System.Windows.Input; 14 | using AuroraAssetEditor.Helpers; 15 | 16 | public partial class TitleAndDbIdDialog { 17 | public TitleAndDbIdDialog(Window owner) { 18 | InitializeComponent(); 19 | Icon = App.WpfIcon; 20 | Owner = owner; 21 | TitleIdBox.Text = GlobalState.CurrentGame.TitleId; 22 | DbIdBox.Text = GlobalState.CurrentGame.DbId; 23 | } 24 | 25 | public string TitleId { get { return TitleIdBox.Text; } } 26 | 27 | public string AssetId { get { return string.Format("{0}_{1}", TitleIdBox.Text, DbIdBox.Text); } } 28 | 29 | private void btnDialogOk_Click(object sender, RoutedEventArgs e) { DialogResult = true; } 30 | 31 | private void OnTextInput(object sender, TextCompositionEventArgs e) { 32 | uint tmp; 33 | e.Handled = !uint.TryParse(e.Text, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out tmp); 34 | } 35 | 36 | private void OnTextChanged(object sender, TextChangedEventArgs e) { 37 | TitleIdBox.Text = Regex.Replace(TitleIdBox.Text, "[^a-fA-F0-9]+", ""); 38 | DbIdBox.Text = Regex.Replace(DbIdBox.Text, "[^a-fA-F0-9]+", ""); 39 | OkButton.IsEnabled = TitleIdBox.Text.Length == 8 && DbIdBox.Text.Length == 8; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /AuroraAssetEditor/msvcr100.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/AuroraAssetEditor/msvcr100.dll -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | v1.2 2 | ~ Fixed a bug with not overwriting the settings JSON file properly with FTP 3 | ~ Fixed a bug with not saving settings without first doing a connection test 4 | ~ Fixed a bug causing issues after ~ 10 minutes of doing nothing 5 | + Added support for keyword search on xbox.com, my observations are that it only searches titles starting with the words you write tho... the search is done on xbox.com, Many thanks to JQE for the support on this! 6 | ~ Fixed a bug causing the application to crash when there's no internet available 7 | - Removed advanced mode -> enabling the settings menu options by default as they're now supported fully (as of Aurora 0.6b they'll not cause any problems) 8 | 9 | v1.1 10 | + Added support for reading FSD Assets file(s) and converting to Aurora assets - Thanks for updating the dll to read dds MaesterRowen 11 | also thanks for helping me with the structure of these files, without you this app wouldn't have existed! 12 | + Added saving all assets in one go - Thanks for the suggestion felida! 13 | + Added support for downloading Assets from xbox.com and/or Xboxunity.net 14 | + Added an icon thanks to RAP7HOR 15 | + Moved all processing to a background thread and added a busy indicator to make the application not freeze and such... 16 | + Added FTP Support, you can now load/save your assets directly from your network using FTP (requires that you are actually running Aurora for it to work) 17 | 18 | v1.0 19 | + Initial release 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AuroraAssetEditor 2 | A Graphical editor for Aurora's .asset files 3 | 4 | There will be more features added to this tool as i find the time to do so, first version only supports reading/writing Aurora .asset files 5 | 6 | [![Build status](https://ci.appveyor.com/api/projects/status/fgyi4apg6s5yp4nl?svg=true)](https://ci.appveyor.com/project/swizzy/auroraasseteditor) 7 | 8 | A Huge thanks goes out to MaesterRowen for explaining the format for me, and also for making the AuroraAsset.dll library which handles the image conversion (between D3DTexture and Bitmap) 9 | Many thanks also goes to Mattie for the placeholder images :) 10 | 11 | Thanks also goes to gavin_darkglider & felida for helping me test this thing :) 12 | 13 | Thanks to RAP7HOR for the icon used in the application as of version 1.1! 14 | -------------------------------------------------------------------------------- /SQLite.Interop/x86/SQLite.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XboxUnity/AuroraAssetEditor/10dd5d94264887d1fed2023280a3b9c070bb88e0/SQLite.Interop/x86/SQLite.Interop.dll -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.4.{build} 2 | image: Visual Studio 2022 3 | skip_tags: true 4 | configuration: Release 5 | 6 | dotnet_csproj: 7 | patch: true 8 | file: '**\*.csproj' 9 | version: '{version}' 10 | file_version: '{version}' 11 | package_version: '{version}' 12 | assembly_version: '{version}' 13 | informational_version: '{version}' 14 | 15 | build_script: 16 | - cmd: dotnet restore 17 | - cmd: dotnet build -c Release 18 | - cmd: dotnet publish -c Release -o publish 19 | - cmd: xcopy C:\projects\auroraasseteditor\SQLite.Interop C:\projects\auroraasseteditor\publish /s 20 | 21 | artifacts: 22 | - path: publish 23 | name: AuroraAssetEditor 24 | 25 | deploy: 26 | - provider: GitHub 27 | tag: v$(APPVEYOR_BUILD_VERSION) 28 | release: Aurora Asset Editor v$(APPVEYOR_BUILD_VERSION) 29 | auth_token: 30 | secure: 1ugGk17lkq2gESnUH82Dt9Mfa1BQT3KUcqbgQHafLlFM9BOAwQMNUlj5h0jNhCwO 31 | artifact: AuroraAssetEditor 32 | draft: true 33 | 34 | #on_finish: 35 | # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 36 | -------------------------------------------------------------------------------- /tools/ParseLocale.py: -------------------------------------------------------------------------------- 1 | import re 2 | import requests 3 | 4 | 5 | def parse_locales(file_data): 6 | locales = [] 7 | for locale_name, locale_var in re.findall( 8 | r'{title:"([^"]+)",locale:([^}]+)}', file_data.decode("utf-8") 9 | ): 10 | locale_id = f"{locale_var[2:4]}-{locale_var[4:]}" 11 | locales.append((locale_id, locale_name)) 12 | return locales 13 | 14 | 15 | def main(): 16 | url = "https://assets-www.xbox.com/xbox-web/static/js/LocalePickerPage.7c45fcf5.chunk.js" 17 | resp = requests.get(url, timeout=60) 18 | resp.raise_for_status() 19 | for locale_id, locale_name in parse_locales(resp.content): 20 | print(f'ret.Add(new XboxLocale("{locale_id}", "{locale_name}"));') 21 | 22 | 23 | if __name__ == "__main__": 24 | main() 25 | --------------------------------------------------------------------------------