├── .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 |
5 |
6 |
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 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
--------------------------------------------------------------------------------