mirror of
https://github.com/Suiranoil/SkinRestorer.git
synced 2026-01-16 04:42:12 +00:00
.editorconfig
This commit is contained in:
262
.editorconfig
Normal file
262
.editorconfig
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = crlf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
tab_width = 4
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
ij_continuation_indent_size = 8
|
||||||
|
|
||||||
|
[*.properties]
|
||||||
|
ij_any_keep_blank_lines_in_code = unset
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
ij_java_align_consecutive_assignments = false
|
||||||
|
ij_java_align_consecutive_variable_declarations = false
|
||||||
|
ij_java_align_group_field_declarations = false
|
||||||
|
ij_java_align_multiline_annotation_parameters = true
|
||||||
|
ij_java_align_multiline_array_initializer_expression = false
|
||||||
|
ij_java_align_multiline_assignment = false
|
||||||
|
ij_java_align_multiline_binary_operation = true
|
||||||
|
ij_java_align_multiline_chained_methods = false
|
||||||
|
ij_java_align_multiline_extends_list = false
|
||||||
|
ij_java_align_multiline_for = true
|
||||||
|
ij_java_align_multiline_method_parentheses = false
|
||||||
|
ij_java_align_multiline_parameters = false
|
||||||
|
ij_java_align_multiline_parameters_in_calls = false
|
||||||
|
ij_java_align_multiline_parenthesized_expression = false
|
||||||
|
ij_java_align_multiline_records = true
|
||||||
|
ij_java_align_multiline_resources = true
|
||||||
|
ij_java_align_multiline_ternary_operation = false
|
||||||
|
ij_java_align_multiline_text_blocks = false
|
||||||
|
ij_java_align_multiline_throws_list = false
|
||||||
|
ij_java_align_subsequent_simple_methods = false
|
||||||
|
ij_java_align_throws_keyword = false
|
||||||
|
ij_java_annotation_parameter_wrap = normal
|
||||||
|
ij_java_array_initializer_new_line_after_left_brace = false
|
||||||
|
ij_java_array_initializer_right_brace_on_new_line = false
|
||||||
|
ij_java_array_initializer_wrap = off
|
||||||
|
ij_java_assert_statement_colon_on_next_line = false
|
||||||
|
ij_java_assert_statement_wrap = off
|
||||||
|
ij_java_assignment_wrap = off
|
||||||
|
ij_java_binary_operation_sign_on_next_line = false
|
||||||
|
ij_java_binary_operation_wrap = off
|
||||||
|
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||||
|
ij_java_blank_lines_after_class_header = 0
|
||||||
|
ij_java_blank_lines_after_imports = 1
|
||||||
|
ij_java_blank_lines_after_package = 1
|
||||||
|
ij_java_blank_lines_around_class = 1
|
||||||
|
ij_java_blank_lines_around_field = 0
|
||||||
|
ij_java_blank_lines_around_field_in_interface = 0
|
||||||
|
ij_java_blank_lines_around_initializer = 1
|
||||||
|
ij_java_blank_lines_around_method = 1
|
||||||
|
ij_java_blank_lines_around_method_in_interface = 1
|
||||||
|
ij_java_blank_lines_before_class_end = 0
|
||||||
|
ij_java_blank_lines_before_imports = 1
|
||||||
|
ij_java_blank_lines_before_method_body = 0
|
||||||
|
ij_java_blank_lines_before_package = 0
|
||||||
|
ij_java_block_brace_style = end_of_line
|
||||||
|
ij_java_block_comment_at_first_column = true
|
||||||
|
ij_java_call_parameters_new_line_after_left_paren = false
|
||||||
|
ij_java_call_parameters_right_paren_on_new_line = false
|
||||||
|
ij_java_call_parameters_wrap = off
|
||||||
|
ij_java_case_statement_on_separate_line = true
|
||||||
|
ij_java_catch_on_new_line = false
|
||||||
|
ij_java_class_annotation_wrap = split_into_lines
|
||||||
|
ij_java_class_brace_style = end_of_line
|
||||||
|
ij_java_class_count_to_use_import_on_demand = 5
|
||||||
|
ij_java_class_names_in_javadoc = 1
|
||||||
|
ij_java_do_not_indent_top_level_class_members = false
|
||||||
|
ij_java_do_not_wrap_after_single_annotation = false
|
||||||
|
ij_java_do_while_brace_force = never
|
||||||
|
ij_java_doc_add_blank_line_after_description = true
|
||||||
|
ij_java_doc_add_blank_line_after_param_comments = false
|
||||||
|
ij_java_doc_add_blank_line_after_return = false
|
||||||
|
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||||
|
ij_java_doc_align_exception_comments = true
|
||||||
|
ij_java_doc_align_param_comments = true
|
||||||
|
ij_java_doc_do_not_wrap_if_one_line = false
|
||||||
|
ij_java_doc_enable_formatting = true
|
||||||
|
ij_java_doc_enable_leading_asterisks = true
|
||||||
|
ij_java_doc_indent_on_continuation = false
|
||||||
|
ij_java_doc_keep_empty_lines = true
|
||||||
|
ij_java_doc_keep_empty_parameter_tag = true
|
||||||
|
ij_java_doc_keep_empty_return_tag = true
|
||||||
|
ij_java_doc_keep_empty_throws_tag = true
|
||||||
|
ij_java_doc_keep_invalid_tags = true
|
||||||
|
ij_java_doc_param_description_on_new_line = false
|
||||||
|
ij_java_doc_preserve_line_breaks = false
|
||||||
|
ij_java_doc_use_throws_not_exception_tag = true
|
||||||
|
ij_java_else_on_new_line = false
|
||||||
|
ij_java_entity_dd_suffix = EJB
|
||||||
|
ij_java_entity_eb_suffix = Bean
|
||||||
|
ij_java_entity_hi_suffix = Home
|
||||||
|
ij_java_entity_lhi_prefix = Local
|
||||||
|
ij_java_entity_lhi_suffix = Home
|
||||||
|
ij_java_entity_li_prefix = Local
|
||||||
|
ij_java_entity_pk_class = java.lang.String
|
||||||
|
ij_java_entity_vo_suffix = VO
|
||||||
|
ij_java_enum_constants_wrap = split_into_lines
|
||||||
|
ij_java_extends_keyword_wrap = off
|
||||||
|
ij_java_extends_list_wrap = off
|
||||||
|
ij_java_field_annotation_wrap = on_every_item
|
||||||
|
ij_java_finally_on_new_line = false
|
||||||
|
ij_java_for_brace_force = never
|
||||||
|
ij_java_for_statement_new_line_after_left_paren = false
|
||||||
|
ij_java_for_statement_right_paren_on_new_line = false
|
||||||
|
ij_java_for_statement_wrap = off
|
||||||
|
ij_java_generate_final_locals = false
|
||||||
|
ij_java_generate_final_parameters = false
|
||||||
|
ij_java_if_brace_force = never
|
||||||
|
ij_java_imports_layout = *, |, javax.**, java.**, |, $*
|
||||||
|
ij_java_indent_case_from_switch = true
|
||||||
|
ij_java_insert_inner_class_imports = false
|
||||||
|
ij_java_insert_override_annotation = true
|
||||||
|
ij_java_keep_blank_lines_before_right_brace = 2
|
||||||
|
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||||
|
ij_java_keep_blank_lines_in_code = 2
|
||||||
|
ij_java_keep_blank_lines_in_declarations = 2
|
||||||
|
ij_java_keep_control_statement_in_one_line = true
|
||||||
|
ij_java_keep_first_column_comment = true
|
||||||
|
ij_java_keep_indents_on_empty_lines = true
|
||||||
|
ij_java_keep_line_breaks = true
|
||||||
|
ij_java_keep_multiple_expressions_in_one_line = false
|
||||||
|
ij_java_keep_simple_blocks_in_one_line = false
|
||||||
|
ij_java_keep_simple_classes_in_one_line = true
|
||||||
|
ij_java_keep_simple_lambdas_in_one_line = true
|
||||||
|
ij_java_keep_simple_methods_in_one_line = true
|
||||||
|
ij_java_label_indent_absolute = false
|
||||||
|
ij_java_label_indent_size = 0
|
||||||
|
ij_java_lambda_brace_style = end_of_line
|
||||||
|
ij_java_layout_static_imports_separately = true
|
||||||
|
ij_java_line_comment_add_space = false
|
||||||
|
ij_java_line_comment_at_first_column = true
|
||||||
|
ij_java_message_dd_suffix = EJB
|
||||||
|
ij_java_message_eb_suffix = Bean
|
||||||
|
ij_java_method_annotation_wrap = split_into_lines
|
||||||
|
ij_java_method_brace_style = end_of_line
|
||||||
|
ij_java_method_call_chain_wrap = off
|
||||||
|
ij_java_method_parameters_new_line_after_left_paren = false
|
||||||
|
ij_java_method_parameters_right_paren_on_new_line = false
|
||||||
|
ij_java_method_parameters_wrap = off
|
||||||
|
ij_java_modifier_list_wrap = false
|
||||||
|
ij_java_names_count_to_use_import_on_demand = 3
|
||||||
|
ij_java_new_line_after_lparen_in_record_header = false
|
||||||
|
ij_java_parameter_annotation_wrap = normal
|
||||||
|
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||||
|
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||||
|
ij_java_place_assignment_sign_on_next_line = false
|
||||||
|
ij_java_prefer_longer_names = true
|
||||||
|
ij_java_prefer_parameters_wrap = false
|
||||||
|
ij_java_record_components_wrap = normal
|
||||||
|
ij_java_repeat_synchronized = true
|
||||||
|
ij_java_replace_instanceof_and_cast = false
|
||||||
|
ij_java_replace_null_check = true
|
||||||
|
ij_java_replace_sum_lambda_with_method_ref = true
|
||||||
|
ij_java_resource_list_new_line_after_left_paren = false
|
||||||
|
ij_java_resource_list_right_paren_on_new_line = false
|
||||||
|
ij_java_resource_list_wrap = off
|
||||||
|
ij_java_rparen_on_new_line_in_record_header = false
|
||||||
|
ij_java_session_dd_suffix = EJB
|
||||||
|
ij_java_session_eb_suffix = Bean
|
||||||
|
ij_java_session_hi_suffix = Home
|
||||||
|
ij_java_session_lhi_prefix = Local
|
||||||
|
ij_java_session_lhi_suffix = Home
|
||||||
|
ij_java_session_li_prefix = Local
|
||||||
|
ij_java_session_si_suffix = Service
|
||||||
|
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||||
|
ij_java_space_after_colon = true
|
||||||
|
ij_java_space_after_comma = true
|
||||||
|
ij_java_space_after_comma_in_type_arguments = true
|
||||||
|
ij_java_space_after_for_semicolon = true
|
||||||
|
ij_java_space_after_quest = true
|
||||||
|
ij_java_space_after_type_cast = true
|
||||||
|
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||||
|
ij_java_space_before_annotation_parameter_list = false
|
||||||
|
ij_java_space_before_array_initializer_left_brace = false
|
||||||
|
ij_java_space_before_catch_keyword = true
|
||||||
|
ij_java_space_before_catch_left_brace = true
|
||||||
|
ij_java_space_before_catch_parentheses = true
|
||||||
|
ij_java_space_before_class_left_brace = true
|
||||||
|
ij_java_space_before_colon = true
|
||||||
|
ij_java_space_before_colon_in_foreach = true
|
||||||
|
ij_java_space_before_comma = false
|
||||||
|
ij_java_space_before_do_left_brace = true
|
||||||
|
ij_java_space_before_else_keyword = true
|
||||||
|
ij_java_space_before_else_left_brace = true
|
||||||
|
ij_java_space_before_finally_keyword = true
|
||||||
|
ij_java_space_before_finally_left_brace = true
|
||||||
|
ij_java_space_before_for_left_brace = true
|
||||||
|
ij_java_space_before_for_parentheses = true
|
||||||
|
ij_java_space_before_for_semicolon = false
|
||||||
|
ij_java_space_before_if_left_brace = true
|
||||||
|
ij_java_space_before_if_parentheses = true
|
||||||
|
ij_java_space_before_method_call_parentheses = false
|
||||||
|
ij_java_space_before_method_left_brace = true
|
||||||
|
ij_java_space_before_method_parentheses = false
|
||||||
|
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||||
|
ij_java_space_before_quest = true
|
||||||
|
ij_java_space_before_switch_left_brace = true
|
||||||
|
ij_java_space_before_switch_parentheses = true
|
||||||
|
ij_java_space_before_synchronized_left_brace = true
|
||||||
|
ij_java_space_before_synchronized_parentheses = true
|
||||||
|
ij_java_space_before_try_left_brace = true
|
||||||
|
ij_java_space_before_try_parentheses = true
|
||||||
|
ij_java_space_before_type_parameter_list = false
|
||||||
|
ij_java_space_before_while_keyword = true
|
||||||
|
ij_java_space_before_while_left_brace = true
|
||||||
|
ij_java_space_before_while_parentheses = true
|
||||||
|
ij_java_space_inside_one_line_enum_braces = false
|
||||||
|
ij_java_space_within_empty_array_initializer_braces = false
|
||||||
|
ij_java_space_within_empty_method_call_parentheses = false
|
||||||
|
ij_java_space_within_empty_method_parentheses = false
|
||||||
|
ij_java_spaces_around_additive_operators = true
|
||||||
|
ij_java_spaces_around_assignment_operators = true
|
||||||
|
ij_java_spaces_around_bitwise_operators = true
|
||||||
|
ij_java_spaces_around_equality_operators = true
|
||||||
|
ij_java_spaces_around_lambda_arrow = true
|
||||||
|
ij_java_spaces_around_logical_operators = true
|
||||||
|
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||||
|
ij_java_spaces_around_multiplicative_operators = true
|
||||||
|
ij_java_spaces_around_relational_operators = true
|
||||||
|
ij_java_spaces_around_shift_operators = true
|
||||||
|
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||||
|
ij_java_spaces_around_unary_operator = false
|
||||||
|
ij_java_spaces_within_angle_brackets = false
|
||||||
|
ij_java_spaces_within_annotation_parentheses = false
|
||||||
|
ij_java_spaces_within_array_initializer_braces = false
|
||||||
|
ij_java_spaces_within_braces = false
|
||||||
|
ij_java_spaces_within_brackets = false
|
||||||
|
ij_java_spaces_within_cast_parentheses = false
|
||||||
|
ij_java_spaces_within_catch_parentheses = false
|
||||||
|
ij_java_spaces_within_for_parentheses = false
|
||||||
|
ij_java_spaces_within_if_parentheses = false
|
||||||
|
ij_java_spaces_within_method_call_parentheses = false
|
||||||
|
ij_java_spaces_within_method_parentheses = false
|
||||||
|
ij_java_spaces_within_parentheses = false
|
||||||
|
ij_java_spaces_within_record_header = false
|
||||||
|
ij_java_spaces_within_switch_parentheses = false
|
||||||
|
ij_java_spaces_within_synchronized_parentheses = false
|
||||||
|
ij_java_spaces_within_try_parentheses = false
|
||||||
|
ij_java_spaces_within_while_parentheses = false
|
||||||
|
ij_java_special_else_if_treatment = true
|
||||||
|
ij_java_subclass_name_suffix = Impl
|
||||||
|
ij_java_ternary_operation_signs_on_next_line = false
|
||||||
|
ij_java_ternary_operation_wrap = off
|
||||||
|
ij_java_test_name_suffix = Test
|
||||||
|
ij_java_throws_keyword_wrap = normal
|
||||||
|
ij_java_throws_list_wrap = off
|
||||||
|
ij_java_use_external_annotations = false
|
||||||
|
ij_java_use_fq_class_names = false
|
||||||
|
ij_java_use_relative_indents = false
|
||||||
|
ij_java_use_single_class_imports = true
|
||||||
|
ij_java_variable_annotation_wrap = normal
|
||||||
|
ij_java_visibility = public
|
||||||
|
ij_java_while_brace_force = never
|
||||||
|
ij_java_while_on_new_line = false
|
||||||
|
ij_java_wrap_comments = false
|
||||||
|
ij_java_wrap_first_method_in_call_chain = false
|
||||||
|
ij_java_wrap_long_lines = false
|
||||||
28
README.md
28
README.md
@@ -1,49 +1,59 @@
|
|||||||
# SkinRestorer
|
# SkinRestorer
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
[](https://www.curseforge.com/minecraft/mc-mods/skinrestorer)
|
[](https://www.curseforge.com/minecraft/mc-mods/skinrestorer)
|
||||||
[](https://modrinth.com/mod/skinrestorer)
|
[](https://modrinth.com/mod/skinrestorer)
|
||||||
|
|
||||||
|
SkinRestorer is a **server-side** only mod for Fabric that allows players to use and change skins on servers running in
|
||||||
SkinRestorer is a **server-side** only mod for Fabric that allows players to use and change skins on servers running in offline/insecure mode.
|
offline/insecure mode.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Set Skins from Mojang Account**: Fetch and apply skins using a valid Minecraft account name.
|
- **Set Skins from Mojang Account**: Fetch and apply skins using a valid Minecraft account name.
|
||||||
- **Set Skins from URL**: Apply skins from any image URL, supporting both classic (Steve) and slim (Alex) skin models.
|
- **Set Skins from URL**: Apply skins from any image URL, supporting both classic (Steve) and slim (Alex) skin models.
|
||||||
|
|
||||||
## Command Usage Guide
|
## Command Usage Guide
|
||||||
|
|
||||||
### Set Mojang Skin
|
### Set Mojang Skin
|
||||||
|
|
||||||
```
|
```
|
||||||
/skin set mojang <skin_name> [<targets>]
|
/skin set mojang <skin_name> [<targets>]
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Parameters:**
|
- **Parameters:**
|
||||||
- `<skin_name>`: Minecraft account name to fetch the skin from.
|
- `<skin_name>`: Minecraft account name to fetch the skin from.
|
||||||
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
||||||
|
|
||||||
### Set Web Skin
|
### Set Web Skin
|
||||||
|
|
||||||
```
|
```
|
||||||
/skin set web (classic|slim) "<url>" [<targets>]
|
/skin set web (classic|slim) "<url>" [<targets>]
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Parameters:**
|
- **Parameters:**
|
||||||
- `(classic|slim)`: Type of the skin model (`classic` for Steve model, `slim` for Alex model).
|
- `(classic|slim)`: Type of the skin model (`classic` for Steve model, `slim` for Alex model).
|
||||||
- `"<url>"`: URL pointing to the skin image file (ensure it follows Minecraft's skin size and format requirements).
|
- `"<url>"`: URL pointing to the skin image file (ensure it follows Minecraft's skin size and format requirements).
|
||||||
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
- `[<targets>]`: (Optional, server operators only) Player(s) to apply the skin to.
|
||||||
|
|
||||||
### Clear Skin
|
### Clear Skin
|
||||||
|
|
||||||
```
|
```
|
||||||
/skin clear [<targets>]
|
/skin clear [<targets>]
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Parameters:**
|
- **Parameters:**
|
||||||
- `[<targets>]`: (Optional, server operators only) Player(s) to clear the skin for.
|
- `[<targets>]`: (Optional, server operators only) Player(s) to clear the skin for.
|
||||||
|
|
||||||
### Notes:
|
### Notes:
|
||||||
|
|
||||||
- If `targets` is not specified, the command will apply to the player executing the command.
|
- If `targets` is not specified, the command will apply to the player executing the command.
|
||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
|
|
||||||
```
|
```
|
||||||
/skin set mojang Notch
|
/skin set mojang Notch
|
||||||
/skin set web classic "http://example.com/skin.png"
|
/skin set web classic "https://example.com/skin.png"
|
||||||
/skin clear @a
|
/skin clear @a
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ import java.io.IOException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public class MineskinSkinProvider {
|
public class MineskinSkinProvider {
|
||||||
|
|
||||||
private static final String API = "https://api.mineskin.org/generate/url";
|
private static final String API = "https://api.mineskin.org/generate/url";
|
||||||
private static final String USER_AGENT = "SkinRestorer";
|
private static final String USER_AGENT = "SkinRestorer";
|
||||||
private static final String TYPE = "application/json";
|
private static final String TYPE = "application/json";
|
||||||
|
|
||||||
public static SkinResult getSkin(String url, SkinVariant variant) {
|
public static SkinResult getSkin(String url, SkinVariant variant) {
|
||||||
try {
|
try {
|
||||||
String input = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}")
|
String input = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}")
|
||||||
.formatted(variant.toString(), "none", 1, url);
|
.formatted(variant.toString(), "none", 1, url);
|
||||||
|
|
||||||
JsonObject texture = JsonUtils.parseJson(WebUtils.POSTRequest(new URL(API), USER_AGENT, TYPE, TYPE, input))
|
JsonObject texture = JsonUtils.parseJson(WebUtils.POSTRequest(new URL(API), USER_AGENT, TYPE, TYPE, input))
|
||||||
.getAsJsonObject("data").getAsJsonObject("texture");
|
.getAsJsonObject("data").getAsJsonObject("texture");
|
||||||
|
|
||||||
return SkinResult.success(new Property("textures", texture.get("value").getAsString(), texture.get("signature").getAsString()));
|
return SkinResult.success(new Property("textures", texture.get("value").getAsString(), texture.get("signature").getAsString()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return SkinResult.error(e);
|
return SkinResult.error(e);
|
||||||
|
|||||||
@@ -10,22 +10,22 @@ import java.net.URL;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class MojangSkinProvider {
|
public class MojangSkinProvider {
|
||||||
|
|
||||||
private static final String API = "https://api.mojang.com/users/profiles/minecraft/";
|
private static final String API = "https://api.mojang.com/users/profiles/minecraft/";
|
||||||
private static final String SESSION_SERVER = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
private static final String SESSION_SERVER = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||||
|
|
||||||
public static SkinResult getSkin(String name) {
|
public static SkinResult getSkin(String name) {
|
||||||
try {
|
try {
|
||||||
UUID uuid = getUUID(name);
|
UUID uuid = getUUID(name);
|
||||||
JsonObject texture = JsonUtils.parseJson(WebUtils.GETRequest(new URL(SESSION_SERVER + uuid + "?unsigned=false")))
|
JsonObject texture = JsonUtils.parseJson(WebUtils.GETRequest(new URL(SESSION_SERVER + uuid + "?unsigned=false")))
|
||||||
.getAsJsonArray("properties").get(0).getAsJsonObject();
|
.getAsJsonArray("properties").get(0).getAsJsonObject();
|
||||||
|
|
||||||
return SkinResult.success(new Property("textures", texture.get("value").getAsString(), texture.get("signature").getAsString()));
|
return SkinResult.success(new Property("textures", texture.get("value").getAsString(), texture.get("signature").getAsString()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return SkinResult.error(e);
|
return SkinResult.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UUID getUUID(String name) throws IOException {
|
private static UUID getUUID(String name) throws IOException {
|
||||||
return UUID.fromString(JsonUtils.parseJson(WebUtils.GETRequest(new URL(API + name))).get("id").getAsString()
|
return UUID.fromString(JsonUtils.parseJson(WebUtils.GETRequest(new URL(API + name))).get("id").getAsString()
|
||||||
.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"));
|
.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"));
|
||||||
|
|||||||
@@ -8,23 +8,23 @@ import java.nio.file.Path;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class SkinIO {
|
public class SkinIO {
|
||||||
|
|
||||||
private static final String FILE_EXTENSION = ".json";
|
private static final String FILE_EXTENSION = ".json";
|
||||||
|
|
||||||
private final Path savePath;
|
private final Path savePath;
|
||||||
|
|
||||||
public SkinIO(Path savePath) {
|
public SkinIO(Path savePath) {
|
||||||
this.savePath = savePath;
|
this.savePath = savePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean skinExists(UUID uuid) {
|
public boolean skinExists(UUID uuid) {
|
||||||
return savePath.resolve(uuid + FILE_EXTENSION).toFile().exists();
|
return savePath.resolve(uuid + FILE_EXTENSION).toFile().exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Property loadSkin(UUID uuid) {
|
public Property loadSkin(UUID uuid) {
|
||||||
return JsonUtils.fromJson(FileUtils.readFile(savePath.resolve(uuid + FILE_EXTENSION).toFile()), Property.class);
|
return JsonUtils.fromJson(FileUtils.readFile(savePath.resolve(uuid + FILE_EXTENSION).toFile()), Property.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveSkin(UUID uuid, Property skin) {
|
public void saveSkin(UUID uuid, Property skin) {
|
||||||
FileUtils.writeFile(savePath.toFile(), uuid + FILE_EXTENSION, JsonUtils.toJson(skin));
|
FileUtils.writeFile(savePath.toFile(), uuid + FILE_EXTENSION, JsonUtils.toJson(skin));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,32 +23,32 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SkinRestorer implements DedicatedServerModInitializer {
|
public class SkinRestorer implements DedicatedServerModInitializer {
|
||||||
|
|
||||||
private static SkinStorage skinStorage;
|
private static SkinStorage skinStorage;
|
||||||
|
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger("SkinRestorer");
|
public static final Logger LOGGER = LoggerFactory.getLogger("SkinRestorer");
|
||||||
|
|
||||||
public static SkinStorage getSkinStorage() {
|
public static SkinStorage getSkinStorage() {
|
||||||
return skinStorage;
|
return skinStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeServer() {
|
public void onInitializeServer() {
|
||||||
skinStorage = new SkinStorage(new SkinIO(FabricLoader.getInstance().getConfigDir().resolve("skinrestorer")));
|
skinStorage = new SkinStorage(new SkinIO(FabricLoader.getInstance().getConfigDir().resolve("skinrestorer")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void refreshPlayer(ServerPlayerEntity player) {
|
public static void refreshPlayer(ServerPlayerEntity player) {
|
||||||
ServerWorld serverWorld = player.getServerWorld();
|
ServerWorld serverWorld = player.getServerWorld();
|
||||||
PlayerManager playerManager = serverWorld.getServer().getPlayerManager();
|
PlayerManager playerManager = serverWorld.getServer().getPlayerManager();
|
||||||
ServerChunkManager chunkManager = serverWorld.getChunkManager();
|
ServerChunkManager chunkManager = serverWorld.getChunkManager();
|
||||||
|
|
||||||
playerManager.sendToAll(new BundleS2CPacket(
|
playerManager.sendToAll(new BundleS2CPacket(
|
||||||
List.of(
|
List.of(
|
||||||
new PlayerRemoveS2CPacket(List.of(player.getUuid())),
|
new PlayerRemoveS2CPacket(List.of(player.getUuid())),
|
||||||
PlayerListS2CPacket.entryFromPlayer(Collections.singleton(player))
|
PlayerListS2CPacket.entryFromPlayer(Collections.singleton(player))
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
if (!player.isDead()) {
|
if (!player.isDead()) {
|
||||||
chunkManager.unloadEntity(player);
|
chunkManager.unloadEntity(player);
|
||||||
chunkManager.loadEntity(player);
|
chunkManager.loadEntity(player);
|
||||||
@@ -68,7 +68,7 @@ public class SkinRestorer implements DedicatedServerModInitializer {
|
|||||||
playerManager.sendStatusEffects(player);
|
playerManager.sendStatusEffects(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>> setSkinAsync(MinecraftServer server, Collection<GameProfile> targets, Supplier<SkinResult> skinSupplier) {
|
public static CompletableFuture<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>> setSkinAsync(MinecraftServer server, Collection<GameProfile> targets, Supplier<SkinResult> skinSupplier) {
|
||||||
return CompletableFuture.<Pair<Property, Collection<GameProfile>>>supplyAsync(() -> {
|
return CompletableFuture.<Pair<Property, Collection<GameProfile>>>supplyAsync(() -> {
|
||||||
SkinResult result = skinSupplier.get();
|
SkinResult result = skinSupplier.get();
|
||||||
@@ -76,28 +76,28 @@ public class SkinRestorer implements DedicatedServerModInitializer {
|
|||||||
SkinRestorer.LOGGER.error("Could not get skin", result.getError());
|
SkinRestorer.LOGGER.error("Could not get skin", result.getError());
|
||||||
return Pair.of(null, Collections.emptySet());
|
return Pair.of(null, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
Property skin = result.getSkin();
|
Property skin = result.getSkin();
|
||||||
|
|
||||||
for (GameProfile profile : targets) {
|
for (GameProfile profile : targets) {
|
||||||
SkinRestorer.getSkinStorage().setSkin(profile.getId(), skin);
|
SkinRestorer.getSkinStorage().setSkin(profile.getId(), skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<GameProfile> acceptedProfiles = new HashSet<>(targets);
|
HashSet<GameProfile> acceptedProfiles = new HashSet<>(targets);
|
||||||
|
|
||||||
return Pair.of(skin, acceptedProfiles);
|
return Pair.of(skin, acceptedProfiles);
|
||||||
}).<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>>thenApplyAsync(pair -> {
|
}).<Pair<Collection<ServerPlayerEntity>, Collection<GameProfile>>>thenApplyAsync(pair -> {
|
||||||
Property skin = pair.left(); // NullPtrException will be caught by 'exceptionally'
|
Property skin = pair.left(); // NullPtrException will be caught by 'exceptionally'
|
||||||
|
|
||||||
Collection<GameProfile> acceptedProfiles = pair.right();
|
Collection<GameProfile> acceptedProfiles = pair.right();
|
||||||
HashSet<ServerPlayerEntity> acceptedPlayers = new HashSet<>();
|
HashSet<ServerPlayerEntity> acceptedPlayers = new HashSet<>();
|
||||||
|
|
||||||
for (GameProfile profile : acceptedProfiles) {
|
for (GameProfile profile : acceptedProfiles) {
|
||||||
ServerPlayerEntity player = server.getPlayerManager().getPlayer(profile.getId());
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(profile.getId());
|
||||||
|
|
||||||
if (player == null || areSkinPropertiesEquals(skin, getPlayerSkin(player)))
|
if (player == null || areSkinPropertiesEquals(skin, getPlayerSkin(player)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
applyRestoredSkin(player.getGameProfile(), skin);
|
applyRestoredSkin(player.getGameProfile(), skin);
|
||||||
refreshPlayer(player);
|
refreshPlayer(player);
|
||||||
acceptedPlayers.add(player);
|
acceptedPlayers.add(player);
|
||||||
@@ -107,48 +107,48 @@ public class SkinRestorer implements DedicatedServerModInitializer {
|
|||||||
.orTimeout(10, TimeUnit.SECONDS)
|
.orTimeout(10, TimeUnit.SECONDS)
|
||||||
.exceptionally(e -> Pair.of(Collections.emptySet(), Collections.emptySet()));
|
.exceptionally(e -> Pair.of(Collections.emptySet(), Collections.emptySet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyRestoredSkin(GameProfile profile, Property skin) {
|
public static void applyRestoredSkin(GameProfile profile, Property skin) {
|
||||||
profile.getProperties().removeAll("textures");
|
profile.getProperties().removeAll("textures");
|
||||||
|
|
||||||
if (skin != null)
|
if (skin != null)
|
||||||
profile.getProperties().put("textures", skin);
|
profile.getProperties().put("textures", skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Property getPlayerSkin(ServerPlayerEntity player) {
|
private static Property getPlayerSkin(ServerPlayerEntity player) {
|
||||||
return player.getGameProfile().getProperties().get("textures").stream().findFirst().orElse(null);
|
return player.getGameProfile().getProperties().get("textures").stream().findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Gson gson = new Gson();
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
private static JsonObject skinPropertyToJson(Property property) {
|
private static JsonObject skinPropertyToJson(Property property) {
|
||||||
try {
|
try {
|
||||||
JsonObject json = gson.fromJson(new String(Base64.getDecoder().decode(property.value()), StandardCharsets.UTF_8), JsonObject.class);
|
JsonObject json = gson.fromJson(new String(Base64.getDecoder().decode(property.value()), StandardCharsets.UTF_8), JsonObject.class);
|
||||||
if (json != null)
|
if (json != null)
|
||||||
json.remove("timestamp");
|
json.remove("timestamp");
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areSkinPropertiesEquals(Property x, Property y) {
|
private static boolean areSkinPropertiesEquals(Property x, Property y) {
|
||||||
if (x == y)
|
if (x == y)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (x == null || y == null)
|
if (x == null || y == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (x.equals(y))
|
if (x.equals(y))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JsonObject xJson = skinPropertyToJson(x);
|
JsonObject xJson = skinPropertyToJson(x);
|
||||||
JsonObject yJson = skinPropertyToJson(y);
|
JsonObject yJson = skinPropertyToJson(y);
|
||||||
|
|
||||||
if (xJson == null || yJson == null)
|
if (xJson == null || yJson == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return xJson.equals(yJson);
|
return xJson.equals(yJson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,40 +6,40 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
public class SkinResult {
|
public class SkinResult {
|
||||||
private final Property skin;
|
private final Property skin;
|
||||||
private final Exception exception;
|
private final Exception exception;
|
||||||
|
|
||||||
private SkinResult(Property skin, Exception exception) {
|
private SkinResult(Property skin, Exception exception) {
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Property getSkin() {
|
public Property getSkin() {
|
||||||
return this.skin;
|
return this.skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Exception getError() {
|
public Exception getError() {
|
||||||
return this.exception;
|
return this.exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isError() {
|
public boolean isError() {
|
||||||
return this.exception != null;
|
return this.exception != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkinResult empty() {
|
public static SkinResult empty() {
|
||||||
return new SkinResult(null, null);
|
return new SkinResult(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkinResult error(Exception e) {
|
public static SkinResult error(Exception e) {
|
||||||
return new SkinResult(null, e);
|
return new SkinResult(null, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkinResult success(@NotNull Property skin) {
|
public static SkinResult success(@NotNull Property skin) {
|
||||||
return new SkinResult(skin, null);
|
return new SkinResult(skin, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SkinResult ofNullable(Property skin) {
|
public static SkinResult ofNullable(Property skin) {
|
||||||
if (skin == null)
|
if (skin == null)
|
||||||
return SkinResult.empty();
|
return SkinResult.empty();
|
||||||
|
|
||||||
return SkinResult.success(skin);
|
return SkinResult.success(skin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,32 +8,32 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class SkinStorage {
|
public class SkinStorage {
|
||||||
|
|
||||||
private final Map<UUID, Optional<Property>> skinMap = new ConcurrentHashMap<>();
|
private final Map<UUID, Optional<Property>> skinMap = new ConcurrentHashMap<>();
|
||||||
private final SkinIO skinIO;
|
private final SkinIO skinIO;
|
||||||
|
|
||||||
public SkinStorage(SkinIO skinIO) {
|
public SkinStorage(SkinIO skinIO) {
|
||||||
this.skinIO = skinIO;
|
this.skinIO = skinIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSavedSkin(UUID uuid) {
|
public boolean hasSavedSkin(UUID uuid) {
|
||||||
return this.skinIO.skinExists(uuid);
|
return this.skinIO.skinExists(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Property getSkin(UUID uuid) {
|
public Property getSkin(UUID uuid) {
|
||||||
if (!skinMap.containsKey(uuid)) {
|
if (!skinMap.containsKey(uuid)) {
|
||||||
Property skin = skinIO.loadSkin(uuid);
|
Property skin = skinIO.loadSkin(uuid);
|
||||||
setSkin(uuid, skin);
|
setSkin(uuid, skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
return skinMap.get(uuid).orElse(null);
|
return skinMap.get(uuid).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSkin(UUID uuid) {
|
public void removeSkin(UUID uuid) {
|
||||||
if (skinMap.containsKey(uuid))
|
if (skinMap.containsKey(uuid))
|
||||||
skinIO.saveSkin(uuid, skinMap.get(uuid).orElse(null));
|
skinIO.saveSkin(uuid, skinMap.get(uuid).orElse(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSkin(UUID uuid, Property skin) {
|
public void setSkin(UUID uuid, Property skin) {
|
||||||
skinMap.put(uuid, Optional.ofNullable(skin));
|
skinMap.put(uuid, Optional.ofNullable(skin));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import static net.minecraft.server.command.CommandManager.argument;
|
|||||||
import static net.minecraft.server.command.CommandManager.literal;
|
import static net.minecraft.server.command.CommandManager.literal;
|
||||||
|
|
||||||
public class SkinCommand {
|
public class SkinCommand {
|
||||||
|
|
||||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||||
dispatcher.register(literal("skin")
|
dispatcher.register(literal("skin")
|
||||||
.then(literal("set")
|
.then(literal("set")
|
||||||
@@ -63,22 +63,22 @@ public class SkinCommand {
|
|||||||
SkinResult::empty))))
|
SkinResult::empty))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int skinAction(ServerCommandSource src, Collection<GameProfile> targets, boolean setByOperator, Supplier<SkinResult> skinSupplier) {
|
private static int skinAction(ServerCommandSource src, Collection<GameProfile> targets, boolean setByOperator, Supplier<SkinResult> skinSupplier) {
|
||||||
SkinRestorer.setSkinAsync(src.getServer(), targets, skinSupplier).thenAccept(pair -> {
|
SkinRestorer.setSkinAsync(src.getServer(), targets, skinSupplier).thenAccept(pair -> {
|
||||||
Collection<GameProfile> profiles = pair.right();
|
Collection<GameProfile> profiles = pair.right();
|
||||||
Collection<ServerPlayerEntity> players = pair.left();
|
Collection<ServerPlayerEntity> players = pair.left();
|
||||||
|
|
||||||
if (profiles.isEmpty()) {
|
if (profiles.isEmpty()) {
|
||||||
src.sendError(Text.of(TranslationUtils.translation.skinActionFailed));
|
src.sendError(Text.of(TranslationUtils.translation.skinActionFailed));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setByOperator) {
|
if (setByOperator) {
|
||||||
src.sendFeedback(() -> Text.of(
|
src.sendFeedback(() -> Text.of(
|
||||||
String.format(TranslationUtils.translation.skinActionAffectedProfile,
|
String.format(TranslationUtils.translation.skinActionAffectedProfile,
|
||||||
String.join(", ", profiles.stream().map(GameProfile::getName).toList()))), true);
|
String.join(", ", profiles.stream().map(GameProfile::getName).toList()))), true);
|
||||||
|
|
||||||
if (!players.isEmpty()) {
|
if (!players.isEmpty()) {
|
||||||
src.sendFeedback(() -> Text.of(
|
src.sendFeedback(() -> Text.of(
|
||||||
String.format(TranslationUtils.translation.skinActionAffectedPlayer,
|
String.format(TranslationUtils.translation.skinActionAffectedPlayer,
|
||||||
@@ -90,11 +90,11 @@ public class SkinCommand {
|
|||||||
});
|
});
|
||||||
return targets.size();
|
return targets.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int skinAction(ServerCommandSource src, Supplier<SkinResult> skinSupplier) {
|
private static int skinAction(ServerCommandSource src, Supplier<SkinResult> skinSupplier) {
|
||||||
if (src.getPlayer() == null)
|
if (src.getPlayer() == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return skinAction(src, Collections.singleton(src.getPlayer().getGameProfile()), false, skinSupplier);
|
return skinAction(src, Collections.singleton(src.getPlayer().getGameProfile()), false, skinSupplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package net.lionarius.skinrestorer.enums;
|
package net.lionarius.skinrestorer.enums;
|
||||||
|
|
||||||
public enum SkinVariant {
|
public enum SkinVariant {
|
||||||
|
|
||||||
CLASSIC("classic"),
|
CLASSIC("classic"),
|
||||||
SLIM("slim");
|
SLIM("slim");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
SkinVariant(String name) {
|
SkinVariant(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
@Mixin(CommandManager.class)
|
@Mixin(CommandManager.class)
|
||||||
public abstract class CommandManagerMixin {
|
public abstract class CommandManagerMixin {
|
||||||
|
|
||||||
@Final @Shadow
|
@Final @Shadow
|
||||||
private CommandDispatcher<ServerCommandSource> dispatcher;
|
private CommandDispatcher<ServerCommandSource> dispatcher;
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/command/AdvancementCommand;register(Lcom/mojang/brigadier/CommandDispatcher;)V"))
|
@Inject(method = "<init>", at = @At(value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/server/command/AdvancementCommand;register(Lcom/mojang/brigadier/CommandDispatcher;)V"))
|
||||||
private void init(CommandManager.RegistrationEnvironment environment, CommandRegistryAccess commandRegistryAccess, CallbackInfo ci) {
|
private void init(CommandManager.RegistrationEnvironment environment, CommandRegistryAccess commandRegistryAccess, CallbackInfo ci) {
|
||||||
SkinCommand.register(dispatcher);
|
SkinCommand.register(dispatcher);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,25 +19,25 @@ import java.util.List;
|
|||||||
|
|
||||||
@Mixin(PlayerManager.class)
|
@Mixin(PlayerManager.class)
|
||||||
public abstract class PlayerManagerMixin {
|
public abstract class PlayerManagerMixin {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract List<ServerPlayerEntity> getPlayerList();
|
public abstract List<ServerPlayerEntity> getPlayerList();
|
||||||
|
|
||||||
@Shadow @Final
|
@Shadow @Final
|
||||||
private MinecraftServer server;
|
private MinecraftServer server;
|
||||||
|
|
||||||
@Inject(method = "remove", at = @At("TAIL"))
|
@Inject(method = "remove", at = @At("TAIL"))
|
||||||
private void remove(ServerPlayerEntity player, CallbackInfo ci) {
|
private void remove(ServerPlayerEntity player, CallbackInfo ci) {
|
||||||
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "disconnectAllPlayers", at = @At("HEAD"))
|
@Inject(method = "disconnectAllPlayers", at = @At("HEAD"))
|
||||||
private void disconnectAllPlayers(CallbackInfo ci) {
|
private void disconnectAllPlayers(CallbackInfo ci) {
|
||||||
for (ServerPlayerEntity player : getPlayerList()) {
|
for (ServerPlayerEntity player : getPlayerList()) {
|
||||||
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
SkinRestorer.getSkinStorage().removeSkin(player.getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "onPlayerConnect", at = @At("HEAD"))
|
@Inject(method = "onPlayerConnect", at = @At("HEAD"))
|
||||||
private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
|
private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
|
||||||
SkinRestorer.setSkinAsync(server, Collections.singleton(player.getGameProfile()), () -> SkinResult.ofNullable(SkinRestorer.getSkinStorage().getSkin(player.getUuid())));
|
SkinRestorer.setSkinAsync(server, Collections.singleton(player.getGameProfile()), () -> SkinResult.ofNullable(SkinRestorer.getSkinStorage().getSkin(player.getUuid())));
|
||||||
|
|||||||
@@ -17,30 +17,32 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
|
|
||||||
@Mixin(ServerLoginNetworkHandler.class)
|
@Mixin(ServerLoginNetworkHandler.class)
|
||||||
public abstract class ServerLoginNetworkHandlerMixin {
|
public abstract class ServerLoginNetworkHandlerMixin {
|
||||||
|
|
||||||
@Shadow @Nullable
|
@Shadow @Nullable
|
||||||
private GameProfile profile;
|
private GameProfile profile;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private CompletableFuture<SkinResult> skinrestorer_pendingSkin;
|
private CompletableFuture<SkinResult> skinrestorer_pendingSkin;
|
||||||
|
|
||||||
@Inject(method = "tickVerify", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;checkCanJoin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/text/Text;"), cancellable = true)
|
@Inject(method = "tickVerify", at = @At(value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/server/PlayerManager;checkCanJoin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/text/Text;"),
|
||||||
|
cancellable = true)
|
||||||
public void waitForSkin(CallbackInfo ci) {
|
public void waitForSkin(CallbackInfo ci) {
|
||||||
if (skinrestorer_pendingSkin == null) {
|
if (skinrestorer_pendingSkin == null) {
|
||||||
skinrestorer_pendingSkin = CompletableFuture.supplyAsync(() -> {
|
skinrestorer_pendingSkin = CompletableFuture.supplyAsync(() -> {
|
||||||
SkinRestorer.LOGGER.debug("Fetching {}'s skin", profile.getName());
|
SkinRestorer.LOGGER.debug("Fetching {}'s skin", profile.getName());
|
||||||
|
|
||||||
if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { // when player joins for the first time fetch Mojang skin by his username
|
if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { // when player joins for the first time fetch Mojang skin by his username
|
||||||
SkinResult result = MojangSkinProvider.getSkin(profile.getName());
|
SkinResult result = MojangSkinProvider.getSkin(profile.getName());
|
||||||
|
|
||||||
if (!result.isError())
|
if (!result.isError())
|
||||||
SkinRestorer.getSkinStorage().setSkin(profile.getId(), result.getSkin());
|
SkinRestorer.getSkinStorage().setSkin(profile.getId(), result.getSkin());
|
||||||
}
|
}
|
||||||
|
|
||||||
return SkinResult.ofNullable(SkinRestorer.getSkinStorage().getSkin(profile.getId()));
|
return SkinResult.ofNullable(SkinRestorer.getSkinStorage().getSkin(profile.getId()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skinrestorer_pendingSkin.isDone())
|
if (!skinrestorer_pendingSkin.isDone())
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import java.io.*;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
public static String readFile(File file) {
|
public static String readFile(File file) {
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(reader);
|
return StringUtils.readString(reader);
|
||||||
@@ -12,16 +12,16 @@ public class FileUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean writeFile(File path, String fileName, String content) {
|
public static boolean writeFile(File path, String fileName, String content) {
|
||||||
try {
|
try {
|
||||||
if (!path.exists())
|
if (!path.exists())
|
||||||
path.mkdirs();
|
path.mkdirs();
|
||||||
|
|
||||||
File file = new File(path, fileName);
|
File file = new File(path, fileName);
|
||||||
if (!file.exists())
|
if (!file.exists())
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
|
|
||||||
try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
|
try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
|
||||||
writer.write(content);
|
writer.write(content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
public class JsonUtils {
|
public class JsonUtils {
|
||||||
|
|
||||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
|
||||||
public static <T> T fromJson(String json, Class<T> clazz) {
|
public static <T> T fromJson(String json, Class<T> clazz) {
|
||||||
return GSON.fromJson(json, clazz);
|
return GSON.fromJson(json, clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toJson(Object obj) {
|
public static String toJson(Object obj) {
|
||||||
return GSON.toJson(obj);
|
return GSON.toJson(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonObject parseJson(String json) {
|
public static JsonObject parseJson(String json) {
|
||||||
return JsonParser.parseString(json).getAsJsonObject();
|
return JsonParser.parseString(json).getAsJsonObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package net.lionarius.skinrestorer.util;
|
|||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
|
||||||
public class PlayerUtils {
|
public class PlayerUtils {
|
||||||
|
|
||||||
public static boolean isFakePlayer(ServerPlayerEntity player) {
|
public static boolean isFakePlayer(ServerPlayerEntity player) {
|
||||||
return player.getClass() != ServerPlayerEntity.class; // if the player isn't a server player entity, it must be someone's fake player
|
return player.getClass() != ServerPlayerEntity.class; // if the player isn't a server player entity, it must be someone's fake player
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
||||||
public static String readString(BufferedReader reader) throws IOException {
|
public static String readString(BufferedReader reader) throws IOException {
|
||||||
String inputLine;
|
String inputLine;
|
||||||
StringBuilder response = new StringBuilder();
|
StringBuilder response = new StringBuilder();
|
||||||
|
|
||||||
while ((inputLine = reader.readLine()) != null) {
|
while ((inputLine = reader.readLine()) != null) {
|
||||||
response.append(inputLine);
|
response.append(inputLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.toString();
|
return response.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ public class TranslationUtils {
|
|||||||
public String skinActionFailed = "Failed to set skin";
|
public String skinActionFailed = "Failed to set skin";
|
||||||
public String skinActionOk = "Skin changed";
|
public String skinActionOk = "Skin changed";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Translation translation = new Translation();
|
public static Translation translation = new Translation();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Path path = FabricLoader.getInstance().getConfigDir().resolve("skinrestorer").resolve("translation.json");
|
Path path = FabricLoader.getInstance().getConfigDir().resolve("skinrestorer").resolve("translation.json");
|
||||||
|
|
||||||
if (Files.exists(path)) {
|
if (Files.exists(path)) {
|
||||||
try {
|
try {
|
||||||
translation = JsonUtils.fromJson(Objects.requireNonNull(FileUtils.readFile(path.toFile())), Translation.class);
|
translation = JsonUtils.fromJson(Objects.requireNonNull(FileUtils.readFile(path.toFile())), Translation.class);
|
||||||
|
|||||||
@@ -9,32 +9,33 @@ import java.net.URL;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class WebUtils {
|
public class WebUtils {
|
||||||
|
|
||||||
public static String POSTRequest(URL url, String userAgent, String contentType, String responseType, String input) throws IOException {
|
public static String POSTRequest(URL url, String userAgent, String contentType, String responseType, String input)
|
||||||
|
throws IOException {
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
connection.setRequestMethod("POST");
|
connection.setRequestMethod("POST");
|
||||||
connection.setRequestProperty("Content-Type", contentType);
|
connection.setRequestProperty("Content-Type", contentType);
|
||||||
connection.setRequestProperty("Accept", responseType);
|
connection.setRequestProperty("Accept", responseType);
|
||||||
connection.setRequestProperty("User-Agent", userAgent);
|
connection.setRequestProperty("User-Agent", userAgent);
|
||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
connection.setDoInput(true);
|
connection.setDoInput(true);
|
||||||
|
|
||||||
try (OutputStream os = connection.getOutputStream()) {
|
try (OutputStream os = connection.getOutputStream()) {
|
||||||
os.write(input.getBytes(StandardCharsets.UTF_8), 0, input.length());
|
os.write(input.getBytes(StandardCharsets.UTF_8), 0, input.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(br);
|
return StringUtils.readString(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String GETRequest(URL url) throws IOException {
|
public static String GETRequest(URL url) throws IOException {
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
connection.setRequestMethod("GET");
|
connection.setRequestMethod("GET");
|
||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
return StringUtils.readString(br);
|
return StringUtils.readString(br);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "skinrestorer",
|
"id": "skinrestorer",
|
||||||
"version": "${version}",
|
"version": "${version}",
|
||||||
"name": "Skin Restorer",
|
"name": "Skin Restorer",
|
||||||
"description": "A server-side mod for restoring skins on offline servers.",
|
"description": "A server-side mod for restoring skins on offline servers.",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Lionarius"
|
"Lionarius"
|
||||||
],
|
],
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://modrinth.com/mod/skinrestorer",
|
"homepage": "https://modrinth.com/mod/skinrestorer",
|
||||||
"sources": "https://github.com/Suiranoil/SkinRestorer",
|
"sources": "https://github.com/Suiranoil/SkinRestorer",
|
||||||
"issues": "https://github.com/Suiranoil/SkinRestorer/issues"
|
"issues": "https://github.com/Suiranoil/SkinRestorer/issues"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"environment": "server",
|
"environment": "server",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"server": [
|
"server": [
|
||||||
"net.lionarius.skinrestorer.SkinRestorer"
|
"net.lionarius.skinrestorer.SkinRestorer"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"skinrestorer.mixins.json"
|
"skinrestorer.mixins.json"
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.15.10",
|
"fabricloader": ">=0.15.10",
|
||||||
"minecraft": "*"
|
"minecraft": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"minVersion": "0.8",
|
"minVersion": "0.8",
|
||||||
"package": "net.lionarius.skinrestorer.mixin",
|
"package": "net.lionarius.skinrestorer.mixin",
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"CommandManagerMixin",
|
"CommandManagerMixin",
|
||||||
"PlayerManagerMixin",
|
"PlayerManagerMixin",
|
||||||
"ServerLoginNetworkHandlerMixin"
|
"ServerLoginNetworkHandlerMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user