├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .idea ├── .gitignore ├── BL3EGSUnlocker.iml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── modules.xml ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── res └── BL3EGSUnlocker.jsonc └── src ├── main.cpp └── unlocker ├── unlocker.cpp └── unlocker.hpp /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = crlf 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 7 | max_line_length = 120 8 | tab_width = 4 9 | ij_continuation_indent_size = 8 10 | ij_formatter_off_tag = @formatter:off 11 | ij_formatter_on_tag = @formatter:on 12 | ij_formatter_tags_enabled = false 13 | ij_smart_tabs = false 14 | ij_visual_guides = none 15 | ij_wrap_on_typing = false 16 | 17 | [.editorconfig] 18 | ij_editorconfig_align_group_field_declarations = false 19 | ij_editorconfig_space_after_colon = false 20 | ij_editorconfig_space_after_comma = true 21 | ij_editorconfig_space_before_colon = false 22 | ij_editorconfig_space_before_comma = false 23 | ij_editorconfig_spaces_around_assignment_operators = true 24 | 25 | [{*.ant,*.fxml,*.icls,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] 26 | ij_xml_align_attributes = true 27 | ij_xml_align_text = false 28 | ij_xml_attribute_wrap = normal 29 | ij_xml_block_comment_add_space = false 30 | ij_xml_block_comment_at_first_column = true 31 | ij_xml_keep_blank_lines = 2 32 | ij_xml_keep_indents_on_empty_lines = false 33 | ij_xml_keep_line_breaks = true 34 | ij_xml_keep_line_breaks_in_text = true 35 | ij_xml_keep_whitespaces = false 36 | ij_xml_keep_whitespaces_around_cdata = preserve 37 | ij_xml_keep_whitespaces_inside_cdata = false 38 | ij_xml_line_comment_at_first_column = true 39 | ij_xml_space_after_tag_name = false 40 | ij_xml_space_around_equals_in_attribute = false 41 | ij_xml_space_inside_empty_tag = false 42 | ij_xml_text_wrap = normal 43 | 44 | [{*.apinotes,*.yaml,*.yml,.clang-format,.clang-tidy,_clang-format}] 45 | indent_size = 2 46 | ij_yaml_align_values_properties = do_not_align 47 | ij_yaml_autoinsert_sequence_marker = true 48 | ij_yaml_block_mapping_on_new_line = false 49 | ij_yaml_indent_sequence_value = true 50 | ij_yaml_keep_indents_on_empty_lines = false 51 | ij_yaml_keep_line_breaks = true 52 | ij_yaml_sequence_on_new_line = false 53 | ij_yaml_space_before_colon = false 54 | ij_yaml_spaces_within_braces = true 55 | ij_yaml_spaces_within_brackets = true 56 | 57 | [{*.bash,*.sh,*.zsh}] 58 | indent_size = 2 59 | tab_width = 2 60 | ij_shell_binary_ops_start_line = false 61 | ij_shell_keep_column_alignment_padding = false 62 | ij_shell_minify_program = false 63 | ij_shell_redirect_followed_by_space = false 64 | ij_shell_switch_cases_indented = false 65 | ij_shell_use_unix_line_separator = true 66 | 67 | [{*.c,*.c++,*.cc,*.cp,*.cpp,*.cu,*.cuh,*.cxx,*.h,*.h++,*.hh,*.hp,*.hpp,*.hxx,*.i,*.icc,*.ii,*.inl,*.ino,*.ipp,*.m,*.mm,*.pch,*.tcc,*.tpp,version.gen.rc}] 68 | ij_visual_guides = 100 69 | ij_continuation_indent_size = 4 70 | ij_c_add_brief_tag = false 71 | ij_c_add_getter_prefix = true 72 | ij_c_add_setter_prefix = true 73 | ij_c_align_dictionary_pair_values = false 74 | ij_c_align_group_field_declarations = false 75 | ij_c_align_init_list_in_columns = true 76 | ij_c_align_multiline_array_initializer_expression = false 77 | ij_c_align_multiline_assignment = true 78 | ij_c_align_multiline_binary_operation = true 79 | ij_c_align_multiline_chained_methods = false 80 | ij_c_align_multiline_for = true 81 | ij_c_align_multiline_ternary_operation = true 82 | ij_c_array_initializer_comma_on_next_line = false 83 | ij_c_array_initializer_new_line_after_left_brace = false 84 | ij_c_array_initializer_right_brace_on_new_line = false 85 | ij_c_array_initializer_wrap = normal 86 | ij_c_assignment_wrap = off 87 | ij_c_binary_operation_sign_on_next_line = false 88 | ij_c_binary_operation_wrap = normal 89 | ij_c_blank_lines_after_class_header = 0 90 | ij_c_blank_lines_after_imports = 0 91 | ij_c_blank_lines_around_class = 1 92 | ij_c_blank_lines_around_field = 0 93 | ij_c_blank_lines_around_field_in_interface = 0 94 | ij_c_blank_lines_around_method = 1 95 | ij_c_blank_lines_around_method_in_interface = 1 96 | ij_c_blank_lines_around_namespace = 0 97 | ij_c_blank_lines_around_properties_in_declaration = 0 98 | ij_c_blank_lines_around_properties_in_interface = 0 99 | ij_c_blank_lines_before_imports = 0 100 | ij_c_blank_lines_before_method_body = 0 101 | ij_c_block_brace_placement = end_of_line 102 | ij_c_block_brace_style = end_of_line 103 | ij_c_block_comment_at_first_column = true 104 | ij_c_catch_on_new_line = false 105 | ij_c_class_brace_style = end_of_line 106 | ij_c_class_constructor_init_list_align_multiline = true 107 | ij_c_class_constructor_init_list_comma_on_next_line = false 108 | ij_c_class_constructor_init_list_new_line_after_colon = never 109 | ij_c_class_constructor_init_list_new_line_before_colon = if_long 110 | ij_c_class_constructor_init_list_wrap = normal 111 | ij_c_copy_is_deep = false 112 | ij_c_create_interface_for_categories = true 113 | ij_c_declare_generated_methods = true 114 | ij_c_description_include_member_names = true 115 | ij_c_discharged_short_ternary_operator = false 116 | ij_c_do_not_add_breaks = false 117 | ij_c_do_while_brace_force = never 118 | ij_c_else_on_new_line = false 119 | ij_c_enum_constants_comma_on_next_line = false 120 | ij_c_enum_constants_wrap = on_every_item 121 | ij_c_for_brace_force = never 122 | ij_c_for_statement_new_line_after_left_paren = false 123 | ij_c_for_statement_right_paren_on_new_line = false 124 | ij_c_for_statement_wrap = off 125 | ij_c_function_brace_placement = end_of_line 126 | ij_c_function_call_arguments_align_multiline = true 127 | ij_c_function_call_arguments_align_multiline_pars = false 128 | ij_c_function_call_arguments_comma_on_next_line = false 129 | ij_c_function_call_arguments_new_line_after_lpar = false 130 | ij_c_function_call_arguments_new_line_before_rpar = false 131 | ij_c_function_call_arguments_wrap = normal 132 | ij_c_function_non_top_after_return_type_wrap = normal 133 | ij_c_function_parameters_align_multiline = true 134 | ij_c_function_parameters_align_multiline_pars = false 135 | ij_c_function_parameters_comma_on_next_line = false 136 | ij_c_function_parameters_new_line_after_lpar = false 137 | ij_c_function_parameters_new_line_before_rpar = false 138 | ij_c_function_parameters_wrap = normal 139 | ij_c_function_top_after_return_type_wrap = normal 140 | ij_c_generate_additional_eq_operators = true 141 | ij_c_generate_additional_rel_operators = true 142 | ij_c_generate_class_constructor = true 143 | ij_c_generate_comparison_operators_use_std_tie = false 144 | ij_c_generate_instance_variables_for_properties = ask 145 | ij_c_generate_operators_as_members = true 146 | ij_c_header_guard_style_pattern = ${PROJECT_NAME}_${FILE_NAME}_${EXT} 147 | ij_c_if_brace_force = never 148 | ij_c_in_line_short_ternary_operator = true 149 | ij_c_indent_block_comment = true 150 | ij_c_indent_c_struct_members = 4 151 | ij_c_indent_case_from_switch = true 152 | ij_c_indent_class_members = 4 153 | ij_c_indent_directive_as_code = false 154 | ij_c_indent_implementation_members = 0 155 | ij_c_indent_inside_code_block = 4 156 | ij_c_indent_interface_members = 0 157 | ij_c_indent_interface_members_except_ivars_block = false 158 | ij_c_indent_namespace_members = 4 159 | ij_c_indent_preprocessor_directive = 0 160 | ij_c_indent_visibility_keywords = 0 161 | ij_c_insert_override = true 162 | ij_c_insert_virtual_with_override = false 163 | ij_c_introduce_auto_vars = false 164 | ij_c_introduce_const_params = false 165 | ij_c_introduce_const_vars = false 166 | ij_c_introduce_generate_property = false 167 | ij_c_introduce_generate_synthesize = true 168 | ij_c_introduce_globals_to_header = true 169 | ij_c_introduce_prop_to_private_category = false 170 | ij_c_introduce_static_consts = true 171 | ij_c_introduce_use_ns_types = false 172 | ij_c_ivars_prefix = _ 173 | ij_c_keep_blank_lines_before_end = 2 174 | ij_c_keep_blank_lines_before_right_brace = 2 175 | ij_c_keep_blank_lines_in_code = 2 176 | ij_c_keep_blank_lines_in_declarations = 2 177 | ij_c_keep_case_expressions_in_one_line = false 178 | ij_c_keep_control_statement_in_one_line = true 179 | ij_c_keep_directive_at_first_column = true 180 | ij_c_keep_first_column_comment = true 181 | ij_c_keep_line_breaks = true 182 | ij_c_keep_nested_namespaces_in_one_line = false 183 | ij_c_keep_simple_blocks_in_one_line = true 184 | ij_c_keep_simple_methods_in_one_line = true 185 | ij_c_keep_structures_in_one_line = false 186 | ij_c_lambda_capture_list_align_multiline = false 187 | ij_c_lambda_capture_list_align_multiline_bracket = false 188 | ij_c_lambda_capture_list_comma_on_next_line = false 189 | ij_c_lambda_capture_list_new_line_after_lbracket = false 190 | ij_c_lambda_capture_list_new_line_before_rbracket = false 191 | ij_c_lambda_capture_list_wrap = off 192 | ij_c_line_comment_add_space = false 193 | ij_c_line_comment_at_first_column = true 194 | ij_c_method_brace_placement = end_of_line 195 | ij_c_method_call_arguments_align_by_colons = true 196 | ij_c_method_call_arguments_align_multiline = false 197 | ij_c_method_call_arguments_special_dictionary_pairs_treatment = true 198 | ij_c_method_call_arguments_wrap = off 199 | ij_c_method_call_chain_wrap = off 200 | ij_c_method_parameters_align_by_colons = true 201 | ij_c_method_parameters_align_multiline = false 202 | ij_c_method_parameters_wrap = off 203 | ij_c_namespace_brace_placement = end_of_line 204 | ij_c_parentheses_expression_new_line_after_left_paren = false 205 | ij_c_parentheses_expression_right_paren_on_new_line = false 206 | ij_c_place_assignment_sign_on_next_line = false 207 | ij_c_property_nonatomic = true 208 | ij_c_put_ivars_to_implementation = true 209 | ij_c_refactor_compatibility_aliases_and_classes = true 210 | ij_c_refactor_properties_and_ivars = true 211 | ij_c_release_style = ivar 212 | ij_c_retain_object_parameters_in_constructor = true 213 | ij_c_semicolon_after_method_signature = false 214 | ij_c_shift_operation_align_multiline = true 215 | ij_c_shift_operation_wrap = normal 216 | ij_c_show_non_virtual_functions = false 217 | ij_c_space_after_colon = true 218 | ij_c_space_after_colon_in_foreach = true 219 | ij_c_space_after_colon_in_selector = false 220 | ij_c_space_after_comma = true 221 | ij_c_space_after_cup_in_blocks = false 222 | ij_c_space_after_dictionary_literal_colon = true 223 | ij_c_space_after_for_semicolon = true 224 | ij_c_space_after_init_list_colon = true 225 | ij_c_space_after_method_parameter_type_parentheses = false 226 | ij_c_space_after_method_return_type_parentheses = false 227 | ij_c_space_after_pointer_in_declaration = true 228 | ij_c_space_after_quest = true 229 | ij_c_space_after_reference_in_declaration = true 230 | ij_c_space_after_reference_in_rvalue = false 231 | ij_c_space_after_structures_rbrace = true 232 | ij_c_space_after_superclass_colon = true 233 | ij_c_space_after_type_cast = true 234 | ij_c_space_after_visibility_sign_in_method_declaration = true 235 | ij_c_space_before_autorelease_pool_lbrace = true 236 | ij_c_space_before_catch_keyword = true 237 | ij_c_space_before_catch_left_brace = true 238 | ij_c_space_before_catch_parentheses = true 239 | ij_c_space_before_category_parentheses = true 240 | ij_c_space_before_chained_send_message = true 241 | ij_c_space_before_class_left_brace = true 242 | ij_c_space_before_colon = true 243 | ij_c_space_before_colon_in_foreach = false 244 | ij_c_space_before_comma = false 245 | ij_c_space_before_dictionary_literal_colon = false 246 | ij_c_space_before_do_left_brace = true 247 | ij_c_space_before_else_keyword = true 248 | ij_c_space_before_else_left_brace = true 249 | ij_c_space_before_for_left_brace = true 250 | ij_c_space_before_for_parentheses = true 251 | ij_c_space_before_for_semicolon = false 252 | ij_c_space_before_if_left_brace = true 253 | ij_c_space_before_if_parentheses = true 254 | ij_c_space_before_init_list = false 255 | ij_c_space_before_init_list_colon = true 256 | ij_c_space_before_method_call_parentheses = false 257 | ij_c_space_before_method_left_brace = true 258 | ij_c_space_before_method_parentheses = false 259 | ij_c_space_before_namespace_lbrace = true 260 | ij_c_space_before_pointer_in_declaration = false 261 | ij_c_space_before_property_attributes_parentheses = false 262 | ij_c_space_before_protocols_brackets = true 263 | ij_c_space_before_quest = true 264 | ij_c_space_before_reference_in_declaration = false 265 | ij_c_space_before_superclass_colon = true 266 | ij_c_space_before_switch_left_brace = true 267 | ij_c_space_before_switch_parentheses = true 268 | ij_c_space_before_template_call_lt = false 269 | ij_c_space_before_template_declaration_lt = false 270 | ij_c_space_before_try_left_brace = true 271 | ij_c_space_before_while_keyword = true 272 | ij_c_space_before_while_left_brace = true 273 | ij_c_space_before_while_parentheses = true 274 | ij_c_space_between_adjacent_brackets = false 275 | ij_c_space_between_operator_and_punctuator = false 276 | ij_c_space_within_empty_array_initializer_braces = false 277 | ij_c_spaces_around_additive_operators = true 278 | ij_c_spaces_around_assignment_operators = true 279 | ij_c_spaces_around_bitwise_operators = true 280 | ij_c_spaces_around_equality_operators = true 281 | ij_c_spaces_around_lambda_arrow = true 282 | ij_c_spaces_around_logical_operators = true 283 | ij_c_spaces_around_multiplicative_operators = true 284 | ij_c_spaces_around_pm_operators = false 285 | ij_c_spaces_around_relational_operators = true 286 | ij_c_spaces_around_shift_operators = true 287 | ij_c_spaces_around_unary_operator = false 288 | ij_c_spaces_within_array_initializer_braces = false 289 | ij_c_spaces_within_braces = true 290 | ij_c_spaces_within_brackets = false 291 | ij_c_spaces_within_cast_parentheses = false 292 | ij_c_spaces_within_catch_parentheses = false 293 | ij_c_spaces_within_category_parentheses = false 294 | ij_c_spaces_within_empty_braces = false 295 | ij_c_spaces_within_empty_function_call_parentheses = false 296 | ij_c_spaces_within_empty_function_declaration_parentheses = false 297 | ij_c_spaces_within_empty_lambda_capture_list_bracket = false 298 | ij_c_spaces_within_empty_template_call_ltgt = false 299 | ij_c_spaces_within_empty_template_declaration_ltgt = false 300 | ij_c_spaces_within_for_parentheses = false 301 | ij_c_spaces_within_function_call_parentheses = false 302 | ij_c_spaces_within_function_declaration_parentheses = false 303 | ij_c_spaces_within_if_parentheses = false 304 | ij_c_spaces_within_lambda_capture_list_bracket = false 305 | ij_c_spaces_within_method_parameter_type_parentheses = false 306 | ij_c_spaces_within_method_return_type_parentheses = false 307 | ij_c_spaces_within_parentheses = false 308 | ij_c_spaces_within_property_attributes_parentheses = false 309 | ij_c_spaces_within_protocols_brackets = false 310 | ij_c_spaces_within_send_message_brackets = false 311 | ij_c_spaces_within_structured_binding_list_bracket = false 312 | ij_c_spaces_within_switch_parentheses = false 313 | ij_c_spaces_within_template_call_ltgt = false 314 | ij_c_spaces_within_template_declaration_ltgt = false 315 | ij_c_spaces_within_template_double_gt = true 316 | ij_c_spaces_within_while_parentheses = false 317 | ij_c_special_else_if_treatment = true 318 | ij_c_structured_binding_list_align_multiline = false 319 | ij_c_structured_binding_list_align_multiline_bracket = false 320 | ij_c_structured_binding_list_comma_on_next_line = false 321 | ij_c_structured_binding_list_new_line_after_lbracket = false 322 | ij_c_structured_binding_list_new_line_before_rbracket = false 323 | ij_c_structured_binding_list_wrap = off 324 | ij_c_superclass_list_after_colon = never 325 | ij_c_superclass_list_align_multiline = true 326 | ij_c_superclass_list_before_colon = if_long 327 | ij_c_superclass_list_comma_on_next_line = false 328 | ij_c_superclass_list_wrap = on_every_item 329 | ij_c_tag_prefix_of_block_comment = at 330 | ij_c_tag_prefix_of_line_comment = back_slash 331 | ij_c_template_call_arguments_align_multiline = false 332 | ij_c_template_call_arguments_align_multiline_pars = false 333 | ij_c_template_call_arguments_comma_on_next_line = false 334 | ij_c_template_call_arguments_new_line_after_lt = false 335 | ij_c_template_call_arguments_new_line_before_gt = false 336 | ij_c_template_call_arguments_wrap = off 337 | ij_c_template_declaration_function_body_indent = false 338 | ij_c_template_declaration_function_wrap = split_into_lines 339 | ij_c_template_declaration_struct_body_indent = false 340 | ij_c_template_declaration_struct_wrap = split_into_lines 341 | ij_c_template_parameters_align_multiline = false 342 | ij_c_template_parameters_align_multiline_pars = false 343 | ij_c_template_parameters_comma_on_next_line = false 344 | ij_c_template_parameters_new_line_after_lt = false 345 | ij_c_template_parameters_new_line_before_gt = false 346 | ij_c_template_parameters_wrap = off 347 | ij_c_ternary_operation_signs_on_next_line = true 348 | ij_c_ternary_operation_wrap = normal 349 | ij_c_type_qualifiers_placement = before 350 | ij_c_use_modern_casts = true 351 | ij_c_use_setters_in_constructor = true 352 | ij_c_while_brace_force = never 353 | ij_c_while_on_new_line = false 354 | ij_c_wrap_property_declaration = off 355 | 356 | [{*.cmake,CMakeLists.txt}] 357 | ij_cmake_align_multiline_parameters_in_calls = false 358 | ij_cmake_force_commands_case = 2 359 | ij_cmake_keep_blank_lines_in_code = 2 360 | ij_cmake_space_before_for_parentheses = true 361 | ij_cmake_space_before_if_parentheses = true 362 | ij_cmake_space_before_method_call_parentheses = false 363 | ij_cmake_space_before_method_parentheses = false 364 | ij_cmake_space_before_while_parentheses = true 365 | ij_cmake_spaces_within_for_parentheses = false 366 | ij_cmake_spaces_within_if_parentheses = false 367 | ij_cmake_spaces_within_method_call_parentheses = false 368 | ij_cmake_spaces_within_method_parentheses = false 369 | ij_cmake_spaces_within_while_parentheses = false 370 | 371 | [{*.har,*.json,*.jsonc}] 372 | indent_size = 2 373 | ij_json_keep_blank_lines_in_code = 0 374 | ij_json_keep_indents_on_empty_lines = false 375 | ij_json_keep_line_breaks = true 376 | ij_json_space_after_colon = true 377 | ij_json_space_after_comma = true 378 | ij_json_space_before_colon = true 379 | ij_json_space_before_comma = false 380 | ij_json_spaces_within_braces = false 381 | ij_json_spaces_within_brackets = false 382 | ij_json_wrap_long_lines = false 383 | 384 | [{*.htm,*.html,*.sht,*.shtm,*.shtml}] 385 | ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 386 | ij_html_align_attributes = true 387 | ij_html_align_text = false 388 | ij_html_attribute_wrap = normal 389 | ij_html_block_comment_add_space = false 390 | ij_html_block_comment_at_first_column = true 391 | ij_html_do_not_align_children_of_min_lines = 0 392 | ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p 393 | ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot 394 | ij_html_enforce_quotes = false 395 | ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var 396 | ij_html_keep_blank_lines = 2 397 | ij_html_keep_indents_on_empty_lines = false 398 | ij_html_keep_line_breaks = true 399 | ij_html_keep_line_breaks_in_text = true 400 | ij_html_keep_whitespaces = false 401 | ij_html_keep_whitespaces_inside = span,pre,textarea 402 | ij_html_line_comment_at_first_column = true 403 | ij_html_new_line_after_last_attribute = never 404 | ij_html_new_line_before_first_attribute = never 405 | ij_html_quote_style = double 406 | ij_html_remove_new_line_before_tags = br 407 | ij_html_space_after_tag_name = false 408 | ij_html_space_around_equality_in_attribute = false 409 | ij_html_space_inside_empty_tag = false 410 | ij_html_text_wrap = normal 411 | 412 | [{*.markdown,*.md}] 413 | ij_markdown_force_one_space_after_blockquote_symbol = true 414 | ij_markdown_force_one_space_after_header_symbol = true 415 | ij_markdown_force_one_space_after_list_bullet = true 416 | ij_markdown_force_one_space_between_words = true 417 | ij_markdown_insert_quote_arrows_on_wrap = true 418 | ij_markdown_keep_indents_on_empty_lines = false 419 | ij_markdown_keep_line_breaks_inside_text_blocks = true 420 | ij_markdown_max_lines_around_block_elements = 1 421 | ij_markdown_max_lines_around_header = 1 422 | ij_markdown_max_lines_between_paragraphs = 1 423 | ij_markdown_min_lines_around_block_elements = 1 424 | ij_markdown_min_lines_around_header = 1 425 | ij_markdown_min_lines_between_paragraphs = 1 426 | ij_markdown_wrap_text_if_long = true 427 | ij_markdown_wrap_text_inside_blockquotes = true 428 | 429 | [{*.ps1,*.psd1,*.psm1,build_debug_32.ps1}] 430 | max_line_length = 115 431 | ij_powershell_align_multiline_binary_operation = false 432 | ij_powershell_align_multiline_chained_methods = false 433 | ij_powershell_align_multiline_for = true 434 | ij_powershell_align_multiline_parameters = true 435 | ij_powershell_align_multiline_parameters_in_calls = false 436 | ij_powershell_binary_operation_wrap = off 437 | ij_powershell_block_brace_style = next_line 438 | ij_powershell_call_parameters_new_line_after_left_paren = false 439 | ij_powershell_call_parameters_right_paren_on_new_line = false 440 | ij_powershell_call_parameters_wrap = off 441 | ij_powershell_catch_on_new_line = true 442 | ij_powershell_class_annotation_wrap = split_into_lines 443 | ij_powershell_class_brace_style = next_line 444 | ij_powershell_else_on_new_line = true 445 | ij_powershell_field_annotation_wrap = off 446 | ij_powershell_finally_on_new_line = true 447 | ij_powershell_for_statement_new_line_after_left_paren = false 448 | ij_powershell_for_statement_right_paren_on_new_line = false 449 | ij_powershell_for_statement_wrap = off 450 | ij_powershell_keep_blank_lines_in_code = 2 451 | ij_powershell_keep_first_column_comment = true 452 | ij_powershell_keep_line_breaks = true 453 | ij_powershell_keep_simple_blocks_in_one_line = false 454 | ij_powershell_keep_simple_classes_in_one_line = false 455 | ij_powershell_keep_simple_lambdas_in_one_line = true 456 | ij_powershell_keep_simple_methods_in_one_line = false 457 | ij_powershell_method_annotation_wrap = split_into_lines 458 | ij_powershell_method_brace_style = next_line 459 | ij_powershell_method_call_chain_wrap = off 460 | ij_powershell_method_parameters_new_line_after_left_paren = false 461 | ij_powershell_method_parameters_right_paren_on_new_line = false 462 | ij_powershell_method_parameters_wrap = off 463 | ij_powershell_parameter_annotation_wrap = off 464 | ij_powershell_parentheses_expression_new_line_after_left_paren = false 465 | ij_powershell_parentheses_expression_right_paren_on_new_line = false 466 | ij_powershell_space_after_colon = true 467 | ij_powershell_space_after_comma = true 468 | ij_powershell_space_after_for_semicolon = true 469 | ij_powershell_space_after_type_cast = false 470 | ij_powershell_space_before_annotation_parameter_list = false 471 | ij_powershell_space_before_array_initializer_left_brace = true 472 | ij_powershell_space_before_catch_keyword = true 473 | ij_powershell_space_before_catch_left_brace = true 474 | ij_powershell_space_before_class_left_brace = true 475 | ij_powershell_space_before_colon = true 476 | ij_powershell_space_before_comma = false 477 | ij_powershell_space_before_do_left_brace = true 478 | ij_powershell_space_before_else_keyword = true 479 | ij_powershell_space_before_else_left_brace = true 480 | ij_powershell_space_before_finally_keyword = true 481 | ij_powershell_space_before_finally_left_brace = true 482 | ij_powershell_space_before_for_left_brace = true 483 | ij_powershell_space_before_for_parentheses = true 484 | ij_powershell_space_before_for_semicolon = false 485 | ij_powershell_space_before_if_left_brace = true 486 | ij_powershell_space_before_if_parentheses = true 487 | ij_powershell_space_before_method_call_parentheses = false 488 | ij_powershell_space_before_method_left_brace = true 489 | ij_powershell_space_before_method_parentheses = false 490 | ij_powershell_space_before_switch_left_brace = true 491 | ij_powershell_space_before_switch_parentheses = true 492 | ij_powershell_space_before_try_left_brace = true 493 | ij_powershell_space_before_while_keyword = true 494 | ij_powershell_space_before_while_left_brace = true 495 | ij_powershell_space_before_while_parentheses = true 496 | ij_powershell_space_within_empty_method_call_parentheses = false 497 | ij_powershell_space_within_empty_method_parentheses = false 498 | ij_powershell_spaces_around_additive_operators = true 499 | ij_powershell_spaces_around_assignment_operators = true 500 | ij_powershell_spaces_around_bitwise_operators = true 501 | ij_powershell_spaces_around_logical_operators = true 502 | ij_powershell_spaces_around_method_ref_dbl_colon = false 503 | ij_powershell_spaces_around_multiplicative_operators = true 504 | ij_powershell_spaces_around_relational_operators = true 505 | ij_powershell_spaces_around_unary_operator = false 506 | ij_powershell_spaces_within_annotation_parentheses = false 507 | ij_powershell_spaces_within_braces = true 508 | ij_powershell_spaces_within_brackets = false 509 | ij_powershell_spaces_within_cast_parentheses = false 510 | ij_powershell_spaces_within_for_parentheses = false 511 | ij_powershell_spaces_within_if_parentheses = false 512 | ij_powershell_spaces_within_method_call_parentheses = false 513 | ij_powershell_spaces_within_method_parentheses = false 514 | ij_powershell_spaces_within_parentheses = false 515 | ij_powershell_spaces_within_switch_parentheses = false 516 | ij_powershell_spaces_within_while_parentheses = false 517 | ij_powershell_special_else_if_treatment = true 518 | ij_powershell_while_on_new_line = false 519 | ij_powershell_wrap_first_method_in_call_chain = false 520 | ij_powershell_wrap_long_lines = false 521 | 522 | [{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] 523 | ij_toml_keep_indents_on_empty_lines = false 524 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | on: push 3 | 4 | jobs: 5 | ci: 6 | name: CI 7 | uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@9035588f1668acdfda8d24b7d0b054e49d4c8f29 8 | permissions: 9 | contents: write 10 | with: 11 | modules: >- 12 | ["Unlocker"] 13 | 14 | zip_command: > 15 | zip -j $ZIP_NAME 16 | artifacts/Unlocker-64/Unlocker.dll 17 | res/BL3EGSUnlocker.jsonc 18 | 19 | config: Release 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea/vcs.xml 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "KoalaBox"] 2 | path = KoalaBox 3 | url = ../../acidicoala/KoalaBox.git 4 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | misc.xml 7 | vcs.xml 8 | -------------------------------------------------------------------------------- /.idea/BL3EGSUnlocker.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 19 | 21 | 22 | 23 | 32 | 33 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.22) 2 | 3 | project(BL3EGSUnlocker VERSION 1.1.1) 4 | 5 | include(KoalaBox/cmake/KoalaBox.cmake) 6 | 7 | add_subdirectory(KoalaBox EXCLUDE_FROM_ALL) 8 | 9 | configure_version_resource("Borderlands 3 EGS DLC Unlocker") 10 | 11 | configure_build_config() 12 | 13 | set(BL3EGSUnlocker_SOURCES src/main.cpp src/unlocker/unlocker.cpp src/unlocker/unlocker.hpp) 14 | 15 | add_library(BL3EGSUnlocker SHARED ${BL3EGSUnlocker_SOURCES} ${VERSION_RESOURCE}) 16 | 17 | configure_output_name(Unlocker) 18 | 19 | configure_include_directories() 20 | 21 | target_link_libraries(BL3EGSUnlocker PRIVATE KoalaBox) 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 by acidicoala 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 7 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 8 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 9 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 10 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 11 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 12 | THIS SOFTWARE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐨 BL3 EGS Unlocker 2 | 3 | **Legit DLC Unlocker for Epic Game Store version of Borderlands 3** 4 | 5 | It works by hooking a function that parses json string of entitlements. 6 | The unlocker automatically fetches DLC IDs and adds them to the original list. 7 | Users can use blacklist option in config to disable automatically fetched DLCs. 8 | Users can also inject additional DLC IDs in the config file. 9 | Config file is entirely optional. All fields within the config file are optional too. 10 | 11 | ## 🛠️ Installation 12 | 13 | * Set up the Koaloader 14 | 1. Download the [latest release](https://github.com/acidicoala/Koaloader/releases/latest) of Koaloader archive 15 | 2. From this archive, unzip the `winmm-64/winmm.dll` file into the `Borderlands3\OakGame\Binaries\Win64` directory 16 | * Set up the Unlocker 17 | 1. Download the [latest release](https://github.com/acidicoala/BL3EGSUnlocker/releases/latest) archive of this unlocker 18 | 2. From this archive, unzip the `Unlocker.dll` file into the `Borderlands3\OakGame\Binaries\Win64` directory 19 | 20 | ## 👋 Acknowledgements 21 | 22 | This unlocker makes use of the following open source projects: 23 | 24 | - [C++ Requests](https://github.com/libcpr/cpr) 25 | - [JSON for Modern C++](https://github.com/nlohmann/json) 26 | - [PolyHook 2](https://github.com/stevemk14ebr/PolyHook_2_0) 27 | - [spdlog](https://github.com/gabime/spdlog) 28 | 29 | ## 📄 License 30 | 31 | This software is licensed under [BSD Zero Clause License], terms of which are available in [LICENSE.txt] 32 | 33 | [BSD Zero Clause License]: https://choosealicense.com/licenses/0bsd/ 34 | 35 | [LICENSE.txt]: LICENSE.txt 36 | -------------------------------------------------------------------------------- /res/BL3EGSUnlocker.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$version": 2, 3 | "logging": false, 4 | "entitlements_pattern": "4C 89 44 24 18 48 89 54 24 10 48 89 4C 24 08 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 F8 48 81 EC ?? ?? ?? ?? 48 8B 5A 08 45 0F B6 F1", 5 | "name_space": "catnip", 6 | "auto_fetch_entitlements": true, 7 | "blacklist": [], 8 | "entitlements": [] 9 | } 10 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | EXTERN_C [[maybe_unused]] BOOL WINAPI DllMain(HMODULE module, DWORD reason, LPVOID) { 4 | if (reason == DLL_PROCESS_ATTACH) { 5 | unlocker::init(module); 6 | } else if (reason == DLL_PROCESS_DETACH) { 7 | unlocker::shutdown(); 8 | } 9 | 10 | return TRUE; 11 | } 12 | -------------------------------------------------------------------------------- /src/unlocker/unlocker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace unlocker { 14 | 15 | struct EntitlementsContainer { 16 | [[maybe_unused]] uint8_t pad10[0x10]; 17 | char* entitlements_json; 18 | uint32_t json_length; 19 | }; 20 | 21 | Config config; // NOLINT(cert-err58-cpp) 22 | 23 | auto make_entitlement(const String& id) { 24 | return nlohmann::json{ 25 | {"id", id}, 26 | {"entitlementName", id}, 27 | {"namespace", config.name_space}, 28 | {"catalogItemId", id}, 29 | {"entitlementType", "AUDIENCE"}, 30 | {"grantDate", "2022-01-01T00:00:00.000Z"}, 31 | {"consumable", false}, 32 | {"status", "ACTIVE"}, 33 | {"useCount", 0}, 34 | {"entitlementSource", "eos"}, 35 | }; 36 | } 37 | 38 | void* parseEntitlements(void* RCX, void* RDX, EntitlementsContainer** R8, bool R9B) { 39 | static const auto parseEntitlements_o = hook::get_original_function(true, nullptr, __func__, parseEntitlements); 40 | logger->debug("{} -> R8: {}", __func__, fmt::ptr(R8)); 41 | 42 | if (not R8 or not*R8 or not(*R8)->entitlements_json) { 43 | logger->warn("Incomplete R8 argument"); 44 | return parseEntitlements_o(RCX, RDX, R8, R9B); 45 | } 46 | 47 | auto* container = *R8; 48 | 49 | const auto original_entitlements_json = container->entitlements_json; 50 | const auto original_json_length = container->json_length; 51 | 52 | const String json_string(original_entitlements_json, original_json_length); 53 | 54 | logger->debug("Original json:\n{}", json_string); 55 | 56 | auto json = nlohmann::json::parse(json_string, nullptr, true, true); 57 | 58 | auto json_contains_entitlement_id = [&](const String& id) { 59 | return std::ranges::any_of(json, [&](const auto& entitlement) { 60 | const auto& catalogItemId = entitlement["catalogItemId"]; 61 | return util::strings_are_equal(catalogItemId, id); 62 | }); 63 | }; 64 | 65 | logger->debug("Original entitlement IDs:", json_string); 66 | for (const auto& entitlement: json) { 67 | logger->debug(" '{}'", entitlement["catalogItemId"]); 68 | } 69 | 70 | if (config.auto_fetch_entitlements) { 71 | nlohmann::json payload = { 72 | {"query", R"(query($namespace: String!) { 73 | Catalog { 74 | catalogOffers( 75 | namespace: $namespace 76 | params: { 77 | count: 1000, 78 | } 79 | ) { 80 | elements { 81 | items { 82 | id, 83 | title 84 | } 85 | } 86 | } 87 | } 88 | })" 89 | }, 90 | {"variables", {{"namespace", config.name_space}}} 91 | }; 92 | 93 | const auto res = cpr::Post( 94 | cpr::Url{"https://graphql.epicgames.com/graphql"}, 95 | cpr::Header{{"content-type", "application/json"}}, 96 | cpr::Body{payload.dump()} 97 | ); 98 | 99 | if (res.status_code == cpr::status::HTTP_OK) { 100 | const auto res_json = nlohmann::json::parse(res.text); 101 | 102 | // logger->debug("Web API entitlements response json:\n{}", res_json.dump(2)); 103 | 104 | const auto& elements = res_json["data"]["Catalog"]["catalogOffers"]["elements"]; 105 | 106 | for (const auto& element: elements) { 107 | for (const auto& items: element) { 108 | for (const auto& item: items) { 109 | const auto& id = item["id"]; 110 | const auto& name = item["title"]; 111 | 112 | // Skip entitlement injection if it is blacklisted or already present 113 | if (config.blacklist.contains(id) or json_contains_entitlement_id(id)) { 114 | continue; 115 | } 116 | 117 | logger->debug("Adding auto-fetched entitlement: '{}' — '{}'", id, name); 118 | json.insert(json.end(), make_entitlement(id)); 119 | } 120 | } 121 | } 122 | } else { 123 | logger->error( 124 | "Failed to automatically fetch entitlement ids. " 125 | "Status code: {}. Text: {}", res.status_code, res.text 126 | ); 127 | } 128 | } 129 | 130 | for (const auto& id: config.entitlements) { 131 | json.insert(json.end(), make_entitlement(id)); 132 | } 133 | 134 | String entitlements_json = json.dump(2); 135 | 136 | // Replace original entitlements with injected 137 | container->entitlements_json = entitlements_json.data(); 138 | container->json_length = entitlements_json.size(); 139 | 140 | logger->info("Injected entitlements:\n{}", container->entitlements_json); 141 | 142 | const auto result = parseEntitlements_o(RCX, RDX, R8, R9B); 143 | 144 | // Restore original entitlements to avoid memory relocation crashes 145 | container->entitlements_json = original_entitlements_json; 146 | container->json_length = original_json_length; 147 | 148 | return result; 149 | } 150 | 151 | void init(const HMODULE& self_module) { 152 | try { 153 | DisableThreadLibraryCalls(self_module); 154 | 155 | koalabox::project_name = PROJECT_NAME; 156 | 157 | const auto self_directory = loader::get_module_dir(self_module); 158 | 159 | config = config_parser::parse(self_directory / PROJECT_NAME".jsonc", true); 160 | 161 | if (config.logging) { 162 | logger = file_logger::create(self_directory / fmt::format("{}.log", PROJECT_NAME)); 163 | } 164 | 165 | logger->info("🐨 {} v{}", PROJECT_NAME, PROJECT_VERSION); 166 | 167 | const auto process_handle = win_util::get_module_handle(nullptr); 168 | const auto process_info = win_util::get_module_info(process_handle); 169 | const auto address = (uint64_t) patcher::find_pattern_address( 170 | process_info, "parseEntitlements", config.entitlements_pattern 171 | ); 172 | 173 | hook::init(true); 174 | hook::detour_or_throw(address, "parseEntitlements", (FunctionAddress) parseEntitlements); 175 | 176 | logger->info("🚀 Initialization complete"); 177 | } catch (const Exception& ex) { 178 | util::panic(fmt::format("Initialization error: {}", ex.what())); 179 | } 180 | } 181 | 182 | void shutdown() { 183 | logger->info("💀 Shutdown complete"); 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /src/unlocker/unlocker.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace unlocker { 8 | using namespace koalabox; 9 | 10 | struct Config { 11 | uint32_t $version = 2; 12 | bool logging = false; 13 | String entitlements_pattern = "4C 89 44 24 18 48 89 54 24 10 48 89 4C 24 08 55" 14 | "53 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 F8" 15 | "48 81 EC ?? ?? ?? ?? 48 8B 5A 08 45 0F B6 F1"; 16 | String name_space = "catnip"; 17 | bool auto_fetch_entitlements = true; 18 | Set blacklist; 19 | Vector entitlements; 20 | 21 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 22 | Config, $version, 23 | logging, 24 | entitlements_pattern, 25 | name_space, 26 | auto_fetch_entitlements, 27 | blacklist, 28 | entitlements 29 | ) 30 | }; 31 | 32 | 33 | void init(const HMODULE& self_module); 34 | 35 | void shutdown(); 36 | 37 | } 38 | --------------------------------------------------------------------------------