Repository: Simplix-Softworks/Cirrus Branch: master Commit: e9d150254681 Files: 128 Total size: 346.5 KB Directory structure: gitextract_6gkla1sj/ ├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── cirrus-bungeecord/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── bungeecord/ │ ├── BungeeCordPlayerWrapper.java │ ├── CirrusBungeeCord.java │ ├── converters/ │ │ ├── ItemModelConverter.java │ │ ├── ItemStackConverter.java │ │ ├── PlayerConverter.java │ │ └── PlayerUniqueIdConverter.java │ ├── listeners/ │ │ └── QuitListener.java │ └── protocolize/ │ └── ProtocolizeMenuBuilder.java ├── cirrus-bungeecord-example/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── dev/ │ │ └── simplix/ │ │ └── cirrus/ │ │ └── bungeecord/ │ │ └── example/ │ │ ├── CirrusExamplePlugin.java │ │ ├── commands/ │ │ │ └── TestCommand.java │ │ └── menus/ │ │ ├── ExampleMenu.java │ │ └── ExampleMultiPageMenu.java │ └── resources/ │ └── plugin.yml ├── cirrus-common/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── dev/ │ │ │ └── simplix/ │ │ │ └── cirrus/ │ │ │ └── common/ │ │ │ ├── Cirrus.java │ │ │ ├── Utils.java │ │ │ ├── business/ │ │ │ │ ├── ConfigurationFactory.java │ │ │ │ ├── DataInventoryMenuItemWrapper.java │ │ │ │ ├── InventoryMenuItemWrapper.java │ │ │ │ ├── MenuItemWrapper.java │ │ │ │ └── PlayerWrapper.java │ │ │ ├── config/ │ │ │ │ └── JsonConfigurationFactory.java │ │ │ ├── configuration/ │ │ │ │ ├── MenuConfiguration.java │ │ │ │ ├── MultiPageMenuConfiguration.java │ │ │ │ └── impl/ │ │ │ │ ├── SimpleMenuConfiguration.java │ │ │ │ └── SimpleMultiPageMenuConfiguration.java │ │ │ ├── container/ │ │ │ │ ├── Container.java │ │ │ │ └── impl/ │ │ │ │ └── ItemContainer.java │ │ │ ├── converter/ │ │ │ │ ├── Converter.java │ │ │ │ └── Converters.java │ │ │ ├── effect/ │ │ │ │ ├── AbstractChangingItemAnimation.java │ │ │ │ ├── AbstractMenuAnimation.java │ │ │ │ ├── Animated.java │ │ │ │ ├── Animations.java │ │ │ │ ├── MenuAnimation.java │ │ │ │ └── MenuAnimator.java │ │ │ ├── effects/ │ │ │ │ ├── GradualColorChangeAnimation.java │ │ │ │ ├── RGBColorChangeAnimation.java │ │ │ │ └── SimpleChangingItemAnimation.java │ │ │ ├── handler/ │ │ │ │ ├── ActionHandler.java │ │ │ │ └── AutoCancellingActionHandler.java │ │ │ ├── i18n/ │ │ │ │ ├── LocalizedItemStackModel.java │ │ │ │ ├── LocalizedString.java │ │ │ │ ├── LocalizedStringDeserializer.java │ │ │ │ ├── LocalizedStringList.java │ │ │ │ ├── LocalizedStringListDeserializer.java │ │ │ │ ├── LocalizedStringListSerializer.java │ │ │ │ ├── LocalizedStringSerializer.java │ │ │ │ ├── Localizer.java │ │ │ │ └── Replacer.java │ │ │ ├── item/ │ │ │ │ ├── CirrusItem.java │ │ │ │ ├── Items.java │ │ │ │ └── ProtocolizeMenuItemWrapper.java │ │ │ ├── menu/ │ │ │ │ ├── AbstractConfigurableMenu.java │ │ │ │ ├── AbstractMenu.java │ │ │ │ ├── ErrorProne.java │ │ │ │ ├── Menu.java │ │ │ │ └── MenuBuilder.java │ │ │ ├── menus/ │ │ │ │ ├── AbstractBrowserMenu.java │ │ │ │ ├── MultiPageMenu.java │ │ │ │ └── SimpleMenu.java │ │ │ ├── model/ │ │ │ │ ├── CallResult.java │ │ │ │ └── Click.java │ │ │ ├── mojangson/ │ │ │ │ ├── MojangsonScope.java │ │ │ │ ├── MojangsonWriter.java │ │ │ │ ├── TagDeserializer.java │ │ │ │ └── TagSerializer.java │ │ │ └── util/ │ │ │ ├── ColorUtils.java │ │ │ ├── Colors.java │ │ │ ├── InventoryContentMap.java │ │ │ └── SafeRunnable.java │ │ └── resources/ │ │ └── cirrus/ │ │ ├── MenuConfiguration.json │ │ └── MultiPageMenuConfiguration.json │ └── test/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── common/ │ └── tests/ │ ├── SnbtGsonTest.java │ └── SnbtTest.java ├── cirrus-spigot/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── spigot/ │ ├── CirrusSpigot.java │ ├── SpigotPlayerWrapper.java │ ├── converters/ │ │ ├── BukkitItemStackConverter.java │ │ ├── ItemModelConverter.java │ │ ├── ItemTypeMaterialDataConverter.java │ │ ├── MaterialDataItemTypeConverter.java │ │ ├── NmsNbtQuerzNbtConverter.java │ │ ├── PlayerConverter.java │ │ ├── ProtocolizeItemStackConverter.java │ │ ├── QuerzNbtNmsNbtConverter.java │ │ ├── SpigotClickTypeConverter.java │ │ └── SpigotInventoryTypeConverter.java │ ├── listener/ │ │ └── InventoryListener.java │ ├── menubuilder/ │ │ └── SpigotMenuBuilder.java │ ├── menus/ │ │ └── SpigotMenu.java │ └── util/ │ ├── BungeeCordComponentConverterProvider.java │ ├── OtherModuleProvider.java │ ├── ProtocolVersionUtil.java │ ├── ProtocolVersions.java │ ├── ReflectionClasses.java │ ├── ReflectionUtil.java │ └── SpigotItemsUtils.java ├── cirrus-spigot-example/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── dev/ │ │ └── simplix/ │ │ └── cirrus/ │ │ └── spigot/ │ │ └── example/ │ │ ├── CirrusExamplePlugin.java │ │ ├── commands/ │ │ │ └── TestCommandExecutor.java │ │ └── menus/ │ │ ├── ExampleMenu.java │ │ └── ExampleMultiPageMenu.java │ └── resources/ │ └── plugin.yml ├── cirrus-spigot-modern/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── spigot/ │ └── modern/ │ └── ModernInventoryView.java ├── cirrus-velocity/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── velocity/ │ ├── CirrusVelocity.java │ ├── VelocityPlayerWrapper.java │ ├── converters/ │ │ ├── ItemModelConverter.java │ │ ├── ItemStackConverter.java │ │ ├── PlayerConverter.java │ │ └── PlayerUniqueIdConverter.java │ ├── listener/ │ │ └── QuitListener.java │ └── protocolize/ │ └── ProtocolizeMenuBuilder.java ├── cirrus-velocity-example/ │ ├── .gitignore │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── dev/ │ └── simplix/ │ └── cirrus/ │ └── velocity/ │ └── example/ │ ├── CirrusExamplePlugin.java │ ├── commands/ │ │ └── TestCommand.java │ └── menus/ │ ├── ExampleMenu.java │ └── ExampleMultiPageMenu.java └── pom.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ [*] charset = utf-8 end_of_line = lf indent_size = 2 indent_style = space insert_final_newline = false max_line_length = 100 tab_width = 2 ij_continuation_indent_size = 4 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on ij_formatter_tags_enabled = false ij_smart_tabs = false ij_visual_guides = 100 ij_wrap_on_typing = true [] ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false ij_json_keep_line_breaks = true ij_json_space_after_colon = true ij_json_space_after_comma = true ij_json_space_before_colon = true ij_json_space_before_comma = false ij_json_spaces_within_braces = false ij_json_spaces_within_brackets = false ij_json_wrap_long_lines = false [*.bib] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_bibtex_keep_first_column_comment = true ij_bibtex_keep_indents_on_empty_lines = false ij_bibtex_wrap_long_lines = false [*.css] ij_css_align_closing_brace_with_properties = false ij_css_blank_lines_around_nested_selector = 1 ij_css_blank_lines_between_blocks = 1 ij_css_brace_placement = end_of_line ij_css_enforce_quotes_on_format = false ij_css_hex_color_long_format = false ij_css_hex_color_lower_case = false ij_css_hex_color_short_format = false ij_css_hex_color_upper_case = false ij_css_keep_blank_lines_in_code = 2 ij_css_keep_indents_on_empty_lines = false ij_css_keep_single_line_blocks = false ij_css_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_css_space_after_colon = true ij_css_space_before_opening_brace = true ij_css_use_double_quotes = true ij_css_value_alignment = do_not_align [*.csv] max_line_length = 2147483647 ij_wrap_on_typing = false ij_csv_wrap_long_lines = false [*.feature] tab_width = 4 ij_continuation_indent_size = 8 ij_gherkin_keep_indents_on_empty_lines = false [*.gsp] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_gsp_keep_indents_on_empty_lines = false [*.haml] tab_width = 4 ij_continuation_indent_size = 8 ij_haml_keep_indents_on_empty_lines = false [*.java] ij_wrap_on_typing = false 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 = false 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 = false 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 = false ij_java_align_multiline_resources = false 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 = off ij_java_array_initializer_new_line_after_left_brace = true ij_java_array_initializer_right_brace_on_new_line = false ij_java_array_initializer_wrap = on_every_item 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 = true ij_java_binary_operation_wrap = on_every_item ij_java_blank_lines_after_anonymous_class_header = 0 ij_java_blank_lines_after_class_header = 1 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 = true ij_java_call_parameters_right_paren_on_new_line = false ij_java_call_parameters_wrap = on_every_item 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 = true 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 = off ij_java_extends_keyword_wrap = off ij_java_extends_list_wrap = on_every_item 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 = true ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = on_every_item ij_java_generate_final_locals = false ij_java_generate_final_parameters = false ij_java_if_brace_force = never ij_java_imports_layout = $*, |, * ij_java_indent_case_from_switch = true ij_java_insert_inner_class_imports = true ij_java_insert_override_annotation = true ij_java_keep_blank_lines_before_right_brace = 1 ij_java_keep_blank_lines_between_package_declaration_and_header = 1 ij_java_keep_blank_lines_in_code = 1 ij_java_keep_blank_lines_in_declarations = 1 ij_java_keep_control_statement_in_one_line = false ij_java_keep_first_column_comment = true ij_java_keep_indents_on_empty_lines = false 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 = false ij_java_keep_simple_lambdas_in_one_line = false ij_java_keep_simple_methods_in_one_line = false 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 = on_every_item ij_java_method_parameters_new_line_after_left_paren = true ij_java_method_parameters_right_paren_on_new_line = false ij_java_method_parameters_wrap = on_every_item ij_java_modifier_list_wrap = false ij_java_names_count_to_use_import_on_demand = 5 ij_java_new_line_after_lparen_in_record_header = true ij_java_parameter_annotation_wrap = off ij_java_parentheses_expression_new_line_after_left_paren = true 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 = on_every_item 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 = true 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_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 = true ij_java_ternary_operation_wrap = on_every_item 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 = off ij_java_visibility = public ij_java_while_brace_force = never ij_java_while_on_new_line = false ij_java_wrap_comments = true ij_java_wrap_first_method_in_call_chain = true ij_java_wrap_long_lines = false [*.less] tab_width = 4 ij_continuation_indent_size = 8 ij_less_align_closing_brace_with_properties = false ij_less_blank_lines_around_nested_selector = 1 ij_less_blank_lines_between_blocks = 1 ij_less_brace_placement = 0 ij_less_enforce_quotes_on_format = false ij_less_hex_color_long_format = false ij_less_hex_color_lower_case = false ij_less_hex_color_short_format = false ij_less_hex_color_upper_case = false ij_less_keep_blank_lines_in_code = 2 ij_less_keep_indents_on_empty_lines = false ij_less_keep_single_line_blocks = false ij_less_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_less_space_after_colon = true ij_less_space_before_opening_brace = true ij_less_use_double_quotes = true ij_less_value_alignment = 0 [*.nbtt] indent_size = 4 max_line_length = 150 tab_width = 4 ij_nbtt_keep_indents_on_empty_lines = false ij_nbtt_space_after_colon = true ij_nbtt_space_after_comma = true ij_nbtt_space_before_colon = true ij_nbtt_space_before_comma = false ij_nbtt_spaces_within_brackets = false ij_nbtt_spaces_within_parentheses = false [*.sass] ij_sass_align_closing_brace_with_properties = false ij_sass_blank_lines_around_nested_selector = 1 ij_sass_blank_lines_between_blocks = 1 ij_sass_brace_placement = 0 ij_sass_enforce_quotes_on_format = false ij_sass_hex_color_long_format = false ij_sass_hex_color_lower_case = false ij_sass_hex_color_short_format = false ij_sass_hex_color_upper_case = false ij_sass_keep_blank_lines_in_code = 2 ij_sass_keep_indents_on_empty_lines = false ij_sass_keep_single_line_blocks = false ij_sass_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_sass_space_after_colon = true ij_sass_space_before_opening_brace = true ij_sass_use_double_quotes = true ij_sass_value_alignment = 0 [*.scss] ij_scss_align_closing_brace_with_properties = false ij_scss_blank_lines_around_nested_selector = 1 ij_scss_blank_lines_between_blocks = 1 ij_scss_brace_placement = 0 ij_scss_enforce_quotes_on_format = false ij_scss_hex_color_long_format = false ij_scss_hex_color_lower_case = false ij_scss_hex_color_short_format = false ij_scss_hex_color_upper_case = false ij_scss_keep_blank_lines_in_code = 2 ij_scss_keep_indents_on_empty_lines = false ij_scss_keep_single_line_blocks = false ij_scss_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_scss_space_after_colon = true ij_scss_space_before_opening_brace = true ij_scss_use_double_quotes = true ij_scss_value_alignment = 0 [*.styl] tab_width = 4 ij_continuation_indent_size = 8 ij_stylus_align_closing_brace_with_properties = false ij_stylus_blank_lines_around_nested_selector = 1 ij_stylus_blank_lines_between_blocks = 1 ij_stylus_brace_placement = 0 ij_stylus_enforce_quotes_on_format = false ij_stylus_hex_color_long_format = false ij_stylus_hex_color_lower_case = false ij_stylus_hex_color_short_format = false ij_stylus_hex_color_upper_case = false ij_stylus_keep_blank_lines_in_code = 2 ij_stylus_keep_indents_on_empty_lines = false ij_stylus_keep_single_line_blocks = false ij_stylus_properties_order = font, font-family, font-size, font-weight, font-style, font-variant, font-size-adjust, font-stretch, line-height, position, z-index, top, right, bottom, left, display, visibility, float, clear, overflow, overflow-x, overflow-y, clip, zoom, align-content, align-items, align-self, flex, flex-flow, flex-basis, flex-direction, flex-grow, flex-shrink, flex-wrap, justify-content, order, box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, table-layout, empty-cells, caption-side, border-spacing, border-collapse, list-style, list-style-position, list-style-type, list-style-image, content, quotes, counter-reset, counter-increment, resize, cursor, user-select, nav-index, nav-up, nav-right, nav-down, nav-left, transition, transition-delay, transition-timing-function, transition-duration, transition-property, transform, transform-origin, animation, animation-name, animation-duration, animation-play-state, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, text-align, text-align-last, vertical-align, white-space, text-decoration, text-emphasis, text-emphasis-color, text-emphasis-style, text-emphasis-position, text-indent, text-justify, letter-spacing, word-spacing, text-outline, text-transform, text-wrap, text-overflow, text-overflow-ellipsis, text-overflow-mode, word-wrap, word-break, tab-size, hyphens, pointer-events, opacity, color, border, border-width, border-style, border-color, border-top, border-top-width, border-top-style, border-top-color, border-right, border-right-width, border-right-style, border-right-color, border-bottom, border-bottom-width, border-bottom-style, border-bottom-color, border-left, border-left-width, border-left-style, border-left-color, border-radius, border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-image, border-image-source, border-image-slice, border-image-width, border-image-outset, border-image-repeat, outline, outline-width, outline-style, outline-color, outline-offset, background, background-color, background-image, background-repeat, background-attachment, background-position, background-position-x, background-position-y, background-clip, background-origin, background-size, box-decoration-break, box-shadow, text-shadow ij_stylus_space_after_colon = true ij_stylus_space_before_opening_brace = true ij_stylus_use_double_quotes = true ij_stylus_value_alignment = 0 [*.tikz] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_latex_keep_first_column_comment = true ij_latex_keep_indents_on_empty_lines = false ij_latex_line_comment_add_space = false ij_latex_line_comment_at_first_column = true ij_latex_wrap_long_lines = false [.editorconfig] ij_editorconfig_align_group_field_declarations = false ij_editorconfig_space_after_colon = false ij_editorconfig_space_after_comma = true ij_editorconfig_space_before_colon = false ij_editorconfig_space_before_comma = false ij_editorconfig_spaces_around_assignment_operators = true [{*.ant, *.bpmn, *.fxml, *.jhm, *.jnlp, *.jrxml, *.plan, *.pom, *.rng, *.tld, *.wadl, *.wsdd, *.wsdl, *.xjb, *.xml, *.xsd, *.xsl, *.xslt, *.xul}] ij_continuation_indent_size = 2 ij_xml_align_attributes = false ij_xml_align_text = false ij_xml_attribute_wrap = normal ij_xml_block_comment_at_first_column = true ij_xml_keep_blank_lines = 2 ij_xml_keep_indents_on_empty_lines = false ij_xml_keep_line_breaks = true ij_xml_keep_line_breaks_in_text = true ij_xml_keep_whitespaces = false ij_xml_keep_whitespaces_around_cdata = preserve ij_xml_keep_whitespaces_inside_cdata = false ij_xml_line_comment_at_first_column = true ij_xml_space_after_tag_name = false ij_xml_space_around_equals_in_attribute = false ij_xml_space_inside_empty_tag = false ij_xml_text_wrap = normal ij_xml_use_custom_settings = true [{*.as, *.es, *.js2}] indent_size = 4 ij_continuation_indent_size = 8 ij_actionscript_align_imports = false ij_actionscript_align_multiline_array_initializer_expression = false ij_actionscript_align_multiline_binary_operation = false ij_actionscript_align_multiline_chained_methods = false ij_actionscript_align_multiline_extends_list = false ij_actionscript_align_multiline_for = false ij_actionscript_align_multiline_parameters = false ij_actionscript_align_multiline_parameters_in_calls = false ij_actionscript_align_multiline_ternary_operation = false ij_actionscript_align_object_properties = 0 ij_actionscript_align_union_types = false ij_actionscript_align_var_statements = 0 ij_actionscript_array_initializer_new_line_after_left_brace = false ij_actionscript_array_initializer_right_brace_on_new_line = false ij_actionscript_array_initializer_wrap = normal ij_actionscript_assignment_wrap = off ij_actionscript_binary_operation_sign_on_next_line = true ij_actionscript_binary_operation_wrap = normal ij_actionscript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_actionscript_blank_lines_after_imports = 1 ij_actionscript_blank_lines_after_package = 0 ij_actionscript_blank_lines_around_function = 1 ij_actionscript_blank_lines_around_method = 1 ij_actionscript_blank_lines_before_imports = 1 ij_actionscript_blank_lines_before_package = 0 ij_actionscript_block_brace_style = end_of_line ij_actionscript_call_parameters_new_line_after_left_paren = false ij_actionscript_call_parameters_right_paren_on_new_line = false ij_actionscript_call_parameters_wrap = normal ij_actionscript_catch_on_new_line = false ij_actionscript_chained_call_dot_on_new_line = true ij_actionscript_class_brace_style = end_of_line ij_actionscript_comma_on_new_line = false ij_actionscript_do_while_brace_force = always ij_actionscript_else_on_new_line = false ij_actionscript_enforce_trailing_comma = keep ij_actionscript_extends_keyword_wrap = off ij_actionscript_extends_list_wrap = normal ij_actionscript_field_prefix = _ ij_actionscript_file_name_style = relaxed ij_actionscript_finally_on_new_line = false ij_actionscript_for_brace_force = always ij_actionscript_for_statement_new_line_after_left_paren = false ij_actionscript_for_statement_right_paren_on_new_line = false ij_actionscript_for_statement_wrap = normal ij_actionscript_force_quote_style = false ij_actionscript_force_semicolon_style = false ij_actionscript_function_expression_brace_style = end_of_line ij_actionscript_if_brace_force = always ij_actionscript_import_merge_members = global ij_actionscript_import_prefer_absolute_path = global ij_actionscript_import_sort_members = true ij_actionscript_import_sort_module_name = false ij_actionscript_import_use_node_resolution = true ij_actionscript_imports_wrap = on_every_item ij_actionscript_indent_case_from_switch = true ij_actionscript_indent_chained_calls = true ij_actionscript_indent_package_children = 0 ij_actionscript_jsx_attribute_value = braces ij_actionscript_keep_blank_lines_in_code = 1 ij_actionscript_keep_first_column_comment = true ij_actionscript_keep_indents_on_empty_lines = false ij_actionscript_keep_line_breaks = true ij_actionscript_keep_simple_blocks_in_one_line = false ij_actionscript_keep_simple_methods_in_one_line = false ij_actionscript_line_comment_at_first_column = true ij_actionscript_method_brace_style = end_of_line ij_actionscript_method_call_chain_wrap = off ij_actionscript_method_parameters_new_line_after_left_paren = false ij_actionscript_method_parameters_right_paren_on_new_line = false ij_actionscript_method_parameters_wrap = normal ij_actionscript_object_literal_wrap = on_every_item ij_actionscript_parentheses_expression_new_line_after_left_paren = false ij_actionscript_parentheses_expression_right_paren_on_new_line = false ij_actionscript_place_assignment_sign_on_next_line = false ij_actionscript_prefer_as_type_cast = false ij_actionscript_prefer_explicit_types_function_expression_returns = false ij_actionscript_prefer_explicit_types_function_returns = false ij_actionscript_prefer_explicit_types_vars_fields = false ij_actionscript_prefer_parameters_wrap = false ij_actionscript_reformat_c_style_comments = false ij_actionscript_space_after_colon = true ij_actionscript_space_after_comma = true ij_actionscript_space_after_dots_in_rest_parameter = false ij_actionscript_space_after_generator_mult = true ij_actionscript_space_after_property_colon = true ij_actionscript_space_after_quest = true ij_actionscript_space_after_type_colon = false ij_actionscript_space_after_unary_not = false ij_actionscript_space_before_async_arrow_lparen = true ij_actionscript_space_before_catch_keyword = true ij_actionscript_space_before_catch_left_brace = true ij_actionscript_space_before_catch_parentheses = true ij_actionscript_space_before_class_lbrace = true ij_actionscript_space_before_colon = true ij_actionscript_space_before_comma = false ij_actionscript_space_before_do_left_brace = true ij_actionscript_space_before_else_keyword = true ij_actionscript_space_before_else_left_brace = true ij_actionscript_space_before_finally_keyword = true ij_actionscript_space_before_finally_left_brace = true ij_actionscript_space_before_for_left_brace = true ij_actionscript_space_before_for_parentheses = true ij_actionscript_space_before_for_semicolon = false ij_actionscript_space_before_function_left_parenth = true ij_actionscript_space_before_generator_mult = false ij_actionscript_space_before_if_left_brace = true ij_actionscript_space_before_if_parentheses = true ij_actionscript_space_before_method_call_parentheses = false ij_actionscript_space_before_method_left_brace = true ij_actionscript_space_before_method_parentheses = false ij_actionscript_space_before_property_colon = false ij_actionscript_space_before_quest = true ij_actionscript_space_before_switch_left_brace = true ij_actionscript_space_before_switch_parentheses = true ij_actionscript_space_before_try_left_brace = true ij_actionscript_space_before_type_colon = false ij_actionscript_space_before_unary_not = false ij_actionscript_space_before_while_keyword = true ij_actionscript_space_before_while_left_brace = true ij_actionscript_space_before_while_parentheses = true ij_actionscript_spaces_around_additive_operators = true ij_actionscript_spaces_around_arrow_function_operator = true ij_actionscript_spaces_around_assignment_operators = true ij_actionscript_spaces_around_bitwise_operators = true ij_actionscript_spaces_around_equality_operators = true ij_actionscript_spaces_around_logical_operators = true ij_actionscript_spaces_around_multiplicative_operators = true ij_actionscript_spaces_around_relational_operators = true ij_actionscript_spaces_around_shift_operators = true ij_actionscript_spaces_around_unary_operator = false ij_actionscript_spaces_within_array_initializer_brackets = false ij_actionscript_spaces_within_brackets = false ij_actionscript_spaces_within_catch_parentheses = false ij_actionscript_spaces_within_for_parentheses = false ij_actionscript_spaces_within_if_parentheses = false ij_actionscript_spaces_within_imports = false ij_actionscript_spaces_within_interpolation_expressions = false ij_actionscript_spaces_within_method_call_parentheses = false ij_actionscript_spaces_within_method_parentheses = false ij_actionscript_spaces_within_object_literal_braces = false ij_actionscript_spaces_within_object_type_braces = true ij_actionscript_spaces_within_parentheses = false ij_actionscript_spaces_within_switch_parentheses = false ij_actionscript_spaces_within_type_assertion = false ij_actionscript_spaces_within_union_types = true ij_actionscript_spaces_within_while_parentheses = false ij_actionscript_special_else_if_treatment = true ij_actionscript_ternary_operation_signs_on_next_line = true ij_actionscript_ternary_operation_wrap = normal ij_actionscript_union_types_wrap = on_every_item ij_actionscript_use_chained_calls_group_indents = false ij_actionscript_use_double_quotes = true ij_actionscript_use_explicit_js_extension = global ij_actionscript_use_path_mapping = always ij_actionscript_use_public_modifier = false ij_actionscript_use_semicolon_after_statement = true ij_actionscript_var_declaration_wrap = normal ij_actionscript_while_brace_force = always ij_actionscript_while_on_new_line = false ij_actionscript_wrap_comments = false [{*.ats, *.ts}] ij_typescript_align_imports = false ij_typescript_align_multiline_array_initializer_expression = false ij_typescript_align_multiline_binary_operation = false ij_typescript_align_multiline_chained_methods = false ij_typescript_align_multiline_extends_list = false ij_typescript_align_multiline_for = true ij_typescript_align_multiline_parameters = true ij_typescript_align_multiline_parameters_in_calls = false ij_typescript_align_multiline_ternary_operation = false ij_typescript_align_object_properties = 0 ij_typescript_align_union_types = false ij_typescript_align_var_statements = 0 ij_typescript_array_initializer_new_line_after_left_brace = false ij_typescript_array_initializer_right_brace_on_new_line = false ij_typescript_array_initializer_wrap = off ij_typescript_assignment_wrap = off ij_typescript_binary_operation_sign_on_next_line = false ij_typescript_binary_operation_wrap = off ij_typescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_typescript_blank_lines_after_imports = 1 ij_typescript_blank_lines_around_class = 1 ij_typescript_blank_lines_around_field = 0 ij_typescript_blank_lines_around_field_in_interface = 0 ij_typescript_blank_lines_around_function = 1 ij_typescript_blank_lines_around_method = 1 ij_typescript_blank_lines_around_method_in_interface = 1 ij_typescript_block_brace_style = end_of_line ij_typescript_call_parameters_new_line_after_left_paren = false ij_typescript_call_parameters_right_paren_on_new_line = false ij_typescript_call_parameters_wrap = off ij_typescript_catch_on_new_line = false ij_typescript_chained_call_dot_on_new_line = true ij_typescript_class_brace_style = end_of_line ij_typescript_comma_on_new_line = false ij_typescript_do_while_brace_force = never ij_typescript_else_on_new_line = false ij_typescript_enforce_trailing_comma = keep ij_typescript_extends_keyword_wrap = off ij_typescript_extends_list_wrap = off ij_typescript_field_prefix = _ ij_typescript_file_name_style = relaxed ij_typescript_finally_on_new_line = false ij_typescript_for_brace_force = never ij_typescript_for_statement_new_line_after_left_paren = false ij_typescript_for_statement_right_paren_on_new_line = false ij_typescript_for_statement_wrap = off ij_typescript_force_quote_style = false ij_typescript_force_semicolon_style = false ij_typescript_function_expression_brace_style = end_of_line ij_typescript_if_brace_force = never ij_typescript_import_merge_members = global ij_typescript_import_prefer_absolute_path = global ij_typescript_import_sort_members = true ij_typescript_import_sort_module_name = false ij_typescript_import_use_node_resolution = true ij_typescript_imports_wrap = on_every_item ij_typescript_indent_case_from_switch = true ij_typescript_indent_chained_calls = false ij_typescript_indent_package_children = 0 ij_typescript_jsdoc_include_types = false ij_typescript_jsx_attribute_value = braces ij_typescript_keep_blank_lines_in_code = 2 ij_typescript_keep_first_column_comment = true ij_typescript_keep_indents_on_empty_lines = false ij_typescript_keep_line_breaks = true ij_typescript_keep_simple_blocks_in_one_line = false ij_typescript_keep_simple_methods_in_one_line = false ij_typescript_line_comment_add_space = true ij_typescript_line_comment_at_first_column = false ij_typescript_method_brace_style = end_of_line ij_typescript_method_call_chain_wrap = off ij_typescript_method_parameters_new_line_after_left_paren = false ij_typescript_method_parameters_right_paren_on_new_line = false ij_typescript_method_parameters_wrap = off ij_typescript_object_literal_wrap = on_every_item ij_typescript_parentheses_expression_new_line_after_left_paren = false ij_typescript_parentheses_expression_right_paren_on_new_line = false ij_typescript_place_assignment_sign_on_next_line = false ij_typescript_prefer_as_type_cast = false ij_typescript_prefer_explicit_types_function_expression_returns = false ij_typescript_prefer_explicit_types_function_returns = false ij_typescript_prefer_explicit_types_vars_fields = false ij_typescript_prefer_parameters_wrap = false ij_typescript_reformat_c_style_comments = false ij_typescript_space_after_colon = true ij_typescript_space_after_comma = true ij_typescript_space_after_dots_in_rest_parameter = false ij_typescript_space_after_generator_mult = true ij_typescript_space_after_property_colon = true ij_typescript_space_after_quest = true ij_typescript_space_after_type_colon = true ij_typescript_space_after_unary_not = false ij_typescript_space_before_async_arrow_lparen = true ij_typescript_space_before_catch_keyword = true ij_typescript_space_before_catch_left_brace = true ij_typescript_space_before_catch_parentheses = true ij_typescript_space_before_class_lbrace = true ij_typescript_space_before_class_left_brace = true ij_typescript_space_before_colon = true ij_typescript_space_before_comma = false ij_typescript_space_before_do_left_brace = true ij_typescript_space_before_else_keyword = true ij_typescript_space_before_else_left_brace = true ij_typescript_space_before_finally_keyword = true ij_typescript_space_before_finally_left_brace = true ij_typescript_space_before_for_left_brace = true ij_typescript_space_before_for_parentheses = true ij_typescript_space_before_for_semicolon = false ij_typescript_space_before_function_left_parenth = true ij_typescript_space_before_generator_mult = false ij_typescript_space_before_if_left_brace = true ij_typescript_space_before_if_parentheses = true ij_typescript_space_before_method_call_parentheses = false ij_typescript_space_before_method_left_brace = true ij_typescript_space_before_method_parentheses = false ij_typescript_space_before_property_colon = false ij_typescript_space_before_quest = true ij_typescript_space_before_switch_left_brace = true ij_typescript_space_before_switch_parentheses = true ij_typescript_space_before_try_left_brace = true ij_typescript_space_before_type_colon = false ij_typescript_space_before_unary_not = false ij_typescript_space_before_while_keyword = true ij_typescript_space_before_while_left_brace = true ij_typescript_space_before_while_parentheses = true ij_typescript_spaces_around_additive_operators = true ij_typescript_spaces_around_arrow_function_operator = true ij_typescript_spaces_around_assignment_operators = true ij_typescript_spaces_around_bitwise_operators = true ij_typescript_spaces_around_equality_operators = true ij_typescript_spaces_around_logical_operators = true ij_typescript_spaces_around_multiplicative_operators = true ij_typescript_spaces_around_relational_operators = true ij_typescript_spaces_around_shift_operators = true ij_typescript_spaces_around_unary_operator = false ij_typescript_spaces_within_array_initializer_brackets = false ij_typescript_spaces_within_brackets = false ij_typescript_spaces_within_catch_parentheses = false ij_typescript_spaces_within_for_parentheses = false ij_typescript_spaces_within_if_parentheses = false ij_typescript_spaces_within_imports = false ij_typescript_spaces_within_interpolation_expressions = false ij_typescript_spaces_within_method_call_parentheses = false ij_typescript_spaces_within_method_parentheses = false ij_typescript_spaces_within_object_literal_braces = false ij_typescript_spaces_within_object_type_braces = true ij_typescript_spaces_within_parentheses = false ij_typescript_spaces_within_switch_parentheses = false ij_typescript_spaces_within_type_assertion = false ij_typescript_spaces_within_union_types = true ij_typescript_spaces_within_while_parentheses = false ij_typescript_special_else_if_treatment = true ij_typescript_ternary_operation_signs_on_next_line = false ij_typescript_ternary_operation_wrap = off ij_typescript_union_types_wrap = on_every_item ij_typescript_use_chained_calls_group_indents = false ij_typescript_use_double_quotes = true ij_typescript_use_explicit_js_extension = global ij_typescript_use_path_mapping = always ij_typescript_use_public_modifier = false ij_typescript_use_semicolon_after_statement = true ij_typescript_var_declaration_wrap = normal ij_typescript_while_brace_force = never ij_typescript_while_on_new_line = false ij_typescript_wrap_comments = false [{*.cfc, *.cfm, *.cfml}] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_cfml_align_multiline_binary_operation = false ij_cfml_align_multiline_for = true ij_cfml_align_multiline_parameters = true ij_cfml_align_multiline_parameters_in_calls = false ij_cfml_align_multiline_ternary_operation = false ij_cfml_assignment_wrap = off ij_cfml_binary_operation_sign_on_next_line = false ij_cfml_binary_operation_wrap = off ij_cfml_block_brace_style = end_of_line ij_cfml_call_parameters_new_line_after_left_paren = false ij_cfml_call_parameters_right_paren_on_new_line = false ij_cfml_call_parameters_wrap = off ij_cfml_catch_on_new_line = false ij_cfml_else_on_new_line = false ij_cfml_for_statement_new_line_after_left_paren = false ij_cfml_for_statement_right_paren_on_new_line = false ij_cfml_for_statement_wrap = off ij_cfml_keep_blank_lines_in_code = 2 ij_cfml_keep_first_column_comment = true ij_cfml_keep_indents_on_empty_lines = false ij_cfml_keep_line_breaks = true ij_cfml_method_brace_style = next_line ij_cfml_method_parameters_new_line_after_left_paren = false ij_cfml_method_parameters_right_paren_on_new_line = false ij_cfml_method_parameters_wrap = off ij_cfml_parentheses_expression_new_line_after_left_paren = false ij_cfml_parentheses_expression_right_paren_on_new_line = false ij_cfml_place_assignment_sign_on_next_line = false ij_cfml_space_after_colon = true ij_cfml_space_after_comma = true ij_cfml_space_after_for_semicolon = true ij_cfml_space_after_quest = true ij_cfml_space_before_catch_keyword = true ij_cfml_space_before_catch_left_brace = true ij_cfml_space_before_catch_parentheses = true ij_cfml_space_before_colon = true ij_cfml_space_before_comma = false ij_cfml_space_before_else_keyword = true ij_cfml_space_before_else_left_brace = true ij_cfml_space_before_for_left_brace = true ij_cfml_space_before_for_parentheses = true ij_cfml_space_before_for_semicolon = false ij_cfml_space_before_if_left_brace = true ij_cfml_space_before_if_parentheses = true ij_cfml_space_before_method_call_parentheses = false ij_cfml_space_before_method_left_brace = true ij_cfml_space_before_method_parentheses = false ij_cfml_space_before_quest = true ij_cfml_space_before_switch_left_brace = true ij_cfml_space_before_switch_parentheses = true ij_cfml_space_before_try_left_brace = true ij_cfml_space_before_while_keyword = true ij_cfml_space_before_while_left_brace = true ij_cfml_space_before_while_parentheses = true ij_cfml_spaces_around_additive_operators = true ij_cfml_spaces_around_assignment_operators = true ij_cfml_spaces_around_equality_operators = true ij_cfml_spaces_around_logical_operators = true ij_cfml_spaces_around_multiplicative_operators = true ij_cfml_spaces_around_relational_operators = true ij_cfml_spaces_around_unary_operator = false ij_cfml_spaces_within_catch_parentheses = false ij_cfml_spaces_within_for_parentheses = false ij_cfml_spaces_within_if_parentheses = false ij_cfml_spaces_within_method_call_parentheses = false ij_cfml_spaces_within_method_parentheses = false ij_cfml_spaces_within_switch_parentheses = false ij_cfml_spaces_within_while_parentheses = false ij_cfml_special_else_if_treatment = false ij_cfml_ternary_operation_signs_on_next_line = false ij_cfml_ternary_operation_wrap = off ij_cfml_while_on_new_line = false [{*.cjs, *.js}] max_line_length = 80 ij_javascript_align_imports = false ij_javascript_align_multiline_array_initializer_expression = false ij_javascript_align_multiline_binary_operation = false ij_javascript_align_multiline_chained_methods = false ij_javascript_align_multiline_extends_list = false ij_javascript_align_multiline_for = false ij_javascript_align_multiline_parameters = false ij_javascript_align_multiline_parameters_in_calls = false ij_javascript_align_multiline_ternary_operation = false ij_javascript_align_object_properties = 0 ij_javascript_align_union_types = false ij_javascript_align_var_statements = 0 ij_javascript_array_initializer_new_line_after_left_brace = false ij_javascript_array_initializer_right_brace_on_new_line = false ij_javascript_array_initializer_wrap = normal ij_javascript_assignment_wrap = off ij_javascript_binary_operation_sign_on_next_line = true ij_javascript_binary_operation_wrap = normal ij_javascript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_javascript_blank_lines_after_imports = 1 ij_javascript_blank_lines_around_class = 1 ij_javascript_blank_lines_around_field = 0 ij_javascript_blank_lines_around_function = 1 ij_javascript_blank_lines_around_method = 1 ij_javascript_block_brace_style = end_of_line ij_javascript_call_parameters_new_line_after_left_paren = false ij_javascript_call_parameters_right_paren_on_new_line = false ij_javascript_call_parameters_wrap = normal ij_javascript_catch_on_new_line = false ij_javascript_chained_call_dot_on_new_line = true ij_javascript_class_brace_style = end_of_line ij_javascript_comma_on_new_line = false ij_javascript_do_while_brace_force = always ij_javascript_else_on_new_line = false ij_javascript_enforce_trailing_comma = keep ij_javascript_extends_keyword_wrap = off ij_javascript_extends_list_wrap = off ij_javascript_field_prefix = _ ij_javascript_file_name_style = relaxed ij_javascript_finally_on_new_line = false ij_javascript_for_brace_force = always ij_javascript_for_statement_new_line_after_left_paren = false ij_javascript_for_statement_right_paren_on_new_line = false ij_javascript_for_statement_wrap = normal ij_javascript_force_quote_style = false ij_javascript_force_semicolon_style = false ij_javascript_function_expression_brace_style = end_of_line ij_javascript_if_brace_force = always ij_javascript_import_merge_members = global ij_javascript_import_prefer_absolute_path = global ij_javascript_import_sort_members = true ij_javascript_import_sort_module_name = false ij_javascript_import_use_node_resolution = true ij_javascript_imports_wrap = on_every_item ij_javascript_indent_case_from_switch = true ij_javascript_indent_chained_calls = false ij_javascript_indent_package_children = 0 ij_javascript_jsx_attribute_value = braces ij_javascript_keep_blank_lines_in_code = 1 ij_javascript_keep_first_column_comment = true ij_javascript_keep_indents_on_empty_lines = false ij_javascript_keep_line_breaks = true ij_javascript_keep_simple_blocks_in_one_line = false ij_javascript_keep_simple_methods_in_one_line = false ij_javascript_line_comment_add_space = true ij_javascript_line_comment_at_first_column = false ij_javascript_method_brace_style = end_of_line ij_javascript_method_call_chain_wrap = off ij_javascript_method_parameters_new_line_after_left_paren = false ij_javascript_method_parameters_right_paren_on_new_line = false ij_javascript_method_parameters_wrap = normal ij_javascript_object_literal_wrap = on_every_item ij_javascript_parentheses_expression_new_line_after_left_paren = false ij_javascript_parentheses_expression_right_paren_on_new_line = false ij_javascript_place_assignment_sign_on_next_line = false ij_javascript_prefer_as_type_cast = false ij_javascript_prefer_explicit_types_function_expression_returns = false ij_javascript_prefer_explicit_types_function_returns = false ij_javascript_prefer_explicit_types_vars_fields = false ij_javascript_prefer_parameters_wrap = false ij_javascript_reformat_c_style_comments = false ij_javascript_space_after_colon = true ij_javascript_space_after_comma = true ij_javascript_space_after_dots_in_rest_parameter = false ij_javascript_space_after_generator_mult = true ij_javascript_space_after_property_colon = true ij_javascript_space_after_quest = true ij_javascript_space_after_type_colon = true ij_javascript_space_after_unary_not = false ij_javascript_space_before_async_arrow_lparen = true ij_javascript_space_before_catch_keyword = true ij_javascript_space_before_catch_left_brace = true ij_javascript_space_before_catch_parentheses = true ij_javascript_space_before_class_lbrace = true ij_javascript_space_before_class_left_brace = true ij_javascript_space_before_colon = true ij_javascript_space_before_comma = false ij_javascript_space_before_do_left_brace = true ij_javascript_space_before_else_keyword = true ij_javascript_space_before_else_left_brace = true ij_javascript_space_before_finally_keyword = true ij_javascript_space_before_finally_left_brace = true ij_javascript_space_before_for_left_brace = true ij_javascript_space_before_for_parentheses = true ij_javascript_space_before_for_semicolon = false ij_javascript_space_before_function_left_parenth = true ij_javascript_space_before_generator_mult = false ij_javascript_space_before_if_left_brace = true ij_javascript_space_before_if_parentheses = true ij_javascript_space_before_method_call_parentheses = false ij_javascript_space_before_method_left_brace = true ij_javascript_space_before_method_parentheses = false ij_javascript_space_before_property_colon = false ij_javascript_space_before_quest = true ij_javascript_space_before_switch_left_brace = true ij_javascript_space_before_switch_parentheses = true ij_javascript_space_before_try_left_brace = true ij_javascript_space_before_type_colon = false ij_javascript_space_before_unary_not = false ij_javascript_space_before_while_keyword = true ij_javascript_space_before_while_left_brace = true ij_javascript_space_before_while_parentheses = true ij_javascript_spaces_around_additive_operators = true ij_javascript_spaces_around_arrow_function_operator = true ij_javascript_spaces_around_assignment_operators = true ij_javascript_spaces_around_bitwise_operators = true ij_javascript_spaces_around_equality_operators = true ij_javascript_spaces_around_logical_operators = true ij_javascript_spaces_around_multiplicative_operators = true ij_javascript_spaces_around_relational_operators = true ij_javascript_spaces_around_shift_operators = true ij_javascript_spaces_around_unary_operator = false ij_javascript_spaces_within_array_initializer_brackets = false ij_javascript_spaces_within_brackets = false ij_javascript_spaces_within_catch_parentheses = false ij_javascript_spaces_within_for_parentheses = false ij_javascript_spaces_within_if_parentheses = false ij_javascript_spaces_within_imports = false ij_javascript_spaces_within_interpolation_expressions = false ij_javascript_spaces_within_method_call_parentheses = false ij_javascript_spaces_within_method_parentheses = false ij_javascript_spaces_within_object_literal_braces = false ij_javascript_spaces_within_object_type_braces = true ij_javascript_spaces_within_parentheses = false ij_javascript_spaces_within_switch_parentheses = false ij_javascript_spaces_within_type_assertion = false ij_javascript_spaces_within_union_types = true ij_javascript_spaces_within_while_parentheses = false ij_javascript_special_else_if_treatment = true ij_javascript_ternary_operation_signs_on_next_line = true ij_javascript_ternary_operation_wrap = normal ij_javascript_union_types_wrap = on_every_item ij_javascript_use_chained_calls_group_indents = false ij_javascript_use_double_quotes = true ij_javascript_use_explicit_js_extension = global ij_javascript_use_path_mapping = always ij_javascript_use_public_modifier = false ij_javascript_use_semicolon_after_statement = true ij_javascript_var_declaration_wrap = normal ij_javascript_while_brace_force = always ij_javascript_while_on_new_line = false ij_javascript_wrap_comments = false [{*.cjsx, *.coffee}] ij_continuation_indent_size = 2 ij_coffeescript_align_function_body = false ij_coffeescript_align_imports = false ij_coffeescript_align_multiline_array_initializer_expression = true ij_coffeescript_align_multiline_parameters = true ij_coffeescript_align_multiline_parameters_in_calls = false ij_coffeescript_align_object_properties = 0 ij_coffeescript_align_union_types = false ij_coffeescript_align_var_statements = 0 ij_coffeescript_array_initializer_new_line_after_left_brace = false ij_coffeescript_array_initializer_right_brace_on_new_line = false ij_coffeescript_array_initializer_wrap = normal ij_coffeescript_blacklist_imports = rxjs/Rx, node_modules/**, **/node_modules/**, @angular/material, @angular/material/typings/** ij_coffeescript_blank_lines_around_function = 1 ij_coffeescript_call_parameters_new_line_after_left_paren = false ij_coffeescript_call_parameters_right_paren_on_new_line = false ij_coffeescript_call_parameters_wrap = normal ij_coffeescript_chained_call_dot_on_new_line = true ij_coffeescript_comma_on_new_line = false ij_coffeescript_enforce_trailing_comma = keep ij_coffeescript_field_prefix = _ ij_coffeescript_file_name_style = relaxed ij_coffeescript_force_quote_style = false ij_coffeescript_force_semicolon_style = false ij_coffeescript_function_expression_brace_style = end_of_line ij_coffeescript_import_merge_members = global ij_coffeescript_import_prefer_absolute_path = global ij_coffeescript_import_sort_members = true ij_coffeescript_import_sort_module_name = false ij_coffeescript_import_use_node_resolution = true ij_coffeescript_imports_wrap = on_every_item ij_coffeescript_indent_chained_calls = true ij_coffeescript_indent_package_children = 0 ij_coffeescript_jsx_attribute_value = braces ij_coffeescript_keep_blank_lines_in_code = 2 ij_coffeescript_keep_first_column_comment = true ij_coffeescript_keep_indents_on_empty_lines = false ij_coffeescript_keep_line_breaks = true ij_coffeescript_keep_simple_methods_in_one_line = false ij_coffeescript_method_parameters_new_line_after_left_paren = false ij_coffeescript_method_parameters_right_paren_on_new_line = false ij_coffeescript_method_parameters_wrap = off ij_coffeescript_object_literal_wrap = on_every_item ij_coffeescript_prefer_as_type_cast = false ij_coffeescript_prefer_explicit_types_function_expression_returns = false ij_coffeescript_prefer_explicit_types_function_returns = false ij_coffeescript_prefer_explicit_types_vars_fields = false ij_coffeescript_reformat_c_style_comments = false ij_coffeescript_space_after_comma = true ij_coffeescript_space_after_dots_in_rest_parameter = false ij_coffeescript_space_after_generator_mult = true ij_coffeescript_space_after_property_colon = true ij_coffeescript_space_after_type_colon = true ij_coffeescript_space_after_unary_not = false ij_coffeescript_space_before_async_arrow_lparen = true ij_coffeescript_space_before_class_lbrace = true ij_coffeescript_space_before_comma = false ij_coffeescript_space_before_function_left_parenth = true ij_coffeescript_space_before_generator_mult = false ij_coffeescript_space_before_property_colon = false ij_coffeescript_space_before_type_colon = false ij_coffeescript_space_before_unary_not = false ij_coffeescript_spaces_around_additive_operators = true ij_coffeescript_spaces_around_arrow_function_operator = true ij_coffeescript_spaces_around_assignment_operators = true ij_coffeescript_spaces_around_bitwise_operators = true ij_coffeescript_spaces_around_equality_operators = true ij_coffeescript_spaces_around_logical_operators = true ij_coffeescript_spaces_around_multiplicative_operators = true ij_coffeescript_spaces_around_relational_operators = true ij_coffeescript_spaces_around_shift_operators = true ij_coffeescript_spaces_around_unary_operator = false ij_coffeescript_spaces_within_array_initializer_braces = false ij_coffeescript_spaces_within_array_initializer_brackets = false ij_coffeescript_spaces_within_imports = false ij_coffeescript_spaces_within_index_brackets = false ij_coffeescript_spaces_within_interpolation_expressions = false ij_coffeescript_spaces_within_method_call_parentheses = false ij_coffeescript_spaces_within_method_parentheses = false ij_coffeescript_spaces_within_object_braces = false ij_coffeescript_spaces_within_object_literal_braces = false ij_coffeescript_spaces_within_object_type_braces = true ij_coffeescript_spaces_within_range_brackets = false ij_coffeescript_spaces_within_type_assertion = false ij_coffeescript_spaces_within_union_types = true ij_coffeescript_union_types_wrap = on_every_item ij_coffeescript_use_chained_calls_group_indents = false ij_coffeescript_use_double_quotes = true ij_coffeescript_use_explicit_js_extension = global ij_coffeescript_use_path_mapping = always ij_coffeescript_use_public_modifier = false ij_coffeescript_use_semicolon_after_statement = false ij_coffeescript_var_declaration_wrap = normal [{*.ft, *.vm, *.vsl}] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_vtl_keep_indents_on_empty_lines = false [{*.gant, *.gradle, *.groovy, *.gson, *.gy}] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_groovy_align_group_field_declarations = false ij_groovy_align_multiline_array_initializer_expression = false ij_groovy_align_multiline_assignment = false ij_groovy_align_multiline_binary_operation = false ij_groovy_align_multiline_chained_methods = false ij_groovy_align_multiline_extends_list = false ij_groovy_align_multiline_for = true ij_groovy_align_multiline_list_or_map = true ij_groovy_align_multiline_method_parentheses = false ij_groovy_align_multiline_parameters = true ij_groovy_align_multiline_parameters_in_calls = false ij_groovy_align_multiline_resources = true ij_groovy_align_multiline_ternary_operation = false ij_groovy_align_multiline_throws_list = false ij_groovy_align_named_args_in_map = true ij_groovy_align_throws_keyword = false ij_groovy_array_initializer_new_line_after_left_brace = false ij_groovy_array_initializer_right_brace_on_new_line = false ij_groovy_array_initializer_wrap = off ij_groovy_assert_statement_wrap = off ij_groovy_assignment_wrap = off ij_groovy_binary_operation_wrap = off ij_groovy_blank_lines_after_class_header = 0 ij_groovy_blank_lines_after_imports = 1 ij_groovy_blank_lines_after_package = 1 ij_groovy_blank_lines_around_class = 1 ij_groovy_blank_lines_around_field = 0 ij_groovy_blank_lines_around_field_in_interface = 0 ij_groovy_blank_lines_around_method = 1 ij_groovy_blank_lines_around_method_in_interface = 1 ij_groovy_blank_lines_before_imports = 1 ij_groovy_blank_lines_before_method_body = 0 ij_groovy_blank_lines_before_package = 0 ij_groovy_block_brace_style = end_of_line ij_groovy_block_comment_at_first_column = true ij_groovy_call_parameters_new_line_after_left_paren = false ij_groovy_call_parameters_right_paren_on_new_line = false ij_groovy_call_parameters_wrap = off ij_groovy_catch_on_new_line = false ij_groovy_class_annotation_wrap = split_into_lines ij_groovy_class_brace_style = end_of_line ij_groovy_class_count_to_use_import_on_demand = 5 ij_groovy_do_while_brace_force = never ij_groovy_else_on_new_line = false ij_groovy_enum_constants_wrap = off ij_groovy_extends_keyword_wrap = off ij_groovy_extends_list_wrap = off ij_groovy_field_annotation_wrap = split_into_lines ij_groovy_finally_on_new_line = false ij_groovy_for_brace_force = never ij_groovy_for_statement_new_line_after_left_paren = false ij_groovy_for_statement_right_paren_on_new_line = false ij_groovy_for_statement_wrap = off ij_groovy_if_brace_force = never ij_groovy_import_annotation_wrap = 2 ij_groovy_indent_case_from_switch = true ij_groovy_indent_label_blocks = true ij_groovy_insert_inner_class_imports = false ij_groovy_keep_blank_lines_before_right_brace = 2 ij_groovy_keep_blank_lines_in_code = 2 ij_groovy_keep_blank_lines_in_declarations = 2 ij_groovy_keep_control_statement_in_one_line = true ij_groovy_keep_first_column_comment = true ij_groovy_keep_indents_on_empty_lines = false ij_groovy_keep_line_breaks = true ij_groovy_keep_multiple_expressions_in_one_line = false ij_groovy_keep_simple_blocks_in_one_line = false ij_groovy_keep_simple_classes_in_one_line = true ij_groovy_keep_simple_lambdas_in_one_line = true ij_groovy_keep_simple_methods_in_one_line = true ij_groovy_label_indent_absolute = false ij_groovy_label_indent_size = 0 ij_groovy_lambda_brace_style = end_of_line ij_groovy_layout_static_imports_separately = true ij_groovy_line_comment_add_space = false ij_groovy_line_comment_at_first_column = true ij_groovy_method_annotation_wrap = split_into_lines ij_groovy_method_brace_style = end_of_line ij_groovy_method_call_chain_wrap = off ij_groovy_method_parameters_new_line_after_left_paren = false ij_groovy_method_parameters_right_paren_on_new_line = false ij_groovy_method_parameters_wrap = off ij_groovy_modifier_list_wrap = false ij_groovy_names_count_to_use_import_on_demand = 3 ij_groovy_parameter_annotation_wrap = off ij_groovy_parentheses_expression_new_line_after_left_paren = false ij_groovy_parentheses_expression_right_paren_on_new_line = false ij_groovy_prefer_parameters_wrap = false ij_groovy_resource_list_new_line_after_left_paren = false ij_groovy_resource_list_right_paren_on_new_line = false ij_groovy_resource_list_wrap = off ij_groovy_space_after_assert_separator = true ij_groovy_space_after_colon = true ij_groovy_space_after_comma = true ij_groovy_space_after_comma_in_type_arguments = true ij_groovy_space_after_for_semicolon = true ij_groovy_space_after_quest = true ij_groovy_space_after_type_cast = true ij_groovy_space_before_annotation_parameter_list = false ij_groovy_space_before_array_initializer_left_brace = false ij_groovy_space_before_assert_separator = false ij_groovy_space_before_catch_keyword = true ij_groovy_space_before_catch_left_brace = true ij_groovy_space_before_catch_parentheses = true ij_groovy_space_before_class_left_brace = true ij_groovy_space_before_closure_left_brace = true ij_groovy_space_before_colon = true ij_groovy_space_before_comma = false ij_groovy_space_before_do_left_brace = true ij_groovy_space_before_else_keyword = true ij_groovy_space_before_else_left_brace = true ij_groovy_space_before_finally_keyword = true ij_groovy_space_before_finally_left_brace = true ij_groovy_space_before_for_left_brace = true ij_groovy_space_before_for_parentheses = true ij_groovy_space_before_for_semicolon = false ij_groovy_space_before_if_left_brace = true ij_groovy_space_before_if_parentheses = true ij_groovy_space_before_method_call_parentheses = false ij_groovy_space_before_method_left_brace = true ij_groovy_space_before_method_parentheses = false ij_groovy_space_before_quest = true ij_groovy_space_before_switch_left_brace = true ij_groovy_space_before_switch_parentheses = true ij_groovy_space_before_synchronized_left_brace = true ij_groovy_space_before_synchronized_parentheses = true ij_groovy_space_before_try_left_brace = true ij_groovy_space_before_try_parentheses = true ij_groovy_space_before_while_keyword = true ij_groovy_space_before_while_left_brace = true ij_groovy_space_before_while_parentheses = true ij_groovy_space_in_named_argument = true ij_groovy_space_in_named_argument_before_colon = false ij_groovy_space_within_empty_array_initializer_braces = false ij_groovy_space_within_empty_method_call_parentheses = false ij_groovy_spaces_around_additive_operators = true ij_groovy_spaces_around_assignment_operators = true ij_groovy_spaces_around_bitwise_operators = true ij_groovy_spaces_around_equality_operators = true ij_groovy_spaces_around_lambda_arrow = true ij_groovy_spaces_around_logical_operators = true ij_groovy_spaces_around_multiplicative_operators = true ij_groovy_spaces_around_regex_operators = true ij_groovy_spaces_around_relational_operators = true ij_groovy_spaces_around_shift_operators = true ij_groovy_spaces_within_annotation_parentheses = false ij_groovy_spaces_within_array_initializer_braces = false ij_groovy_spaces_within_braces = true ij_groovy_spaces_within_brackets = false ij_groovy_spaces_within_cast_parentheses = false ij_groovy_spaces_within_catch_parentheses = false ij_groovy_spaces_within_for_parentheses = false ij_groovy_spaces_within_gstring_injection_braces = false ij_groovy_spaces_within_if_parentheses = false ij_groovy_spaces_within_list_or_map = false ij_groovy_spaces_within_method_call_parentheses = false ij_groovy_spaces_within_method_parentheses = false ij_groovy_spaces_within_parentheses = false ij_groovy_spaces_within_switch_parentheses = false ij_groovy_spaces_within_synchronized_parentheses = false ij_groovy_spaces_within_try_parentheses = false ij_groovy_spaces_within_tuple_expression = false ij_groovy_spaces_within_while_parentheses = false ij_groovy_special_else_if_treatment = true ij_groovy_ternary_operation_wrap = off ij_groovy_throws_keyword_wrap = off ij_groovy_throws_list_wrap = off ij_groovy_use_flying_geese_braces = false ij_groovy_use_fq_class_names = false ij_groovy_use_fq_class_names_in_javadoc = true ij_groovy_use_relative_indents = false ij_groovy_use_single_class_imports = true ij_groovy_variable_annotation_wrap = off ij_groovy_while_brace_force = never ij_groovy_while_on_new_line = false ij_groovy_wrap_long_lines = false [{*.gradle.kts, *.kt, *.kts, *.main.kts}] ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false ij_kotlin_align_multiline_method_parentheses = false ij_kotlin_align_multiline_parameters = true ij_kotlin_align_multiline_parameters_in_calls = false ij_kotlin_assignment_wrap = on_every_item ij_kotlin_blank_lines_after_class_header = 0 ij_kotlin_blank_lines_around_block_when_branches = 0 ij_kotlin_block_comment_at_first_column = true ij_kotlin_call_parameters_new_line_after_left_paren = true ij_kotlin_call_parameters_right_paren_on_new_line = false ij_kotlin_call_parameters_wrap = on_every_item ij_kotlin_catch_on_new_line = false ij_kotlin_class_annotation_wrap = split_into_lines ij_kotlin_continuation_indent_for_chained_calls = true ij_kotlin_continuation_indent_for_expression_bodies = true ij_kotlin_continuation_indent_in_argument_lists = true ij_kotlin_continuation_indent_in_elvis = true ij_kotlin_continuation_indent_in_if_conditions = true ij_kotlin_continuation_indent_in_parameter_lists = true ij_kotlin_continuation_indent_in_supertype_lists = true ij_kotlin_else_on_new_line = false ij_kotlin_enum_constants_wrap = off ij_kotlin_extends_list_wrap = on_every_item ij_kotlin_field_annotation_wrap = split_into_lines ij_kotlin_finally_on_new_line = false ij_kotlin_if_rparen_on_new_line = false ij_kotlin_import_nested_classes = false ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_keep_blank_lines_before_right_brace = 1 ij_kotlin_keep_blank_lines_in_code = 1 ij_kotlin_keep_blank_lines_in_declarations = 1 ij_kotlin_keep_first_column_comment = true ij_kotlin_keep_indents_on_empty_lines = false ij_kotlin_keep_line_breaks = true ij_kotlin_lbrace_on_next_line = false ij_kotlin_line_comment_add_space = false ij_kotlin_line_comment_at_first_column = true ij_kotlin_method_annotation_wrap = split_into_lines ij_kotlin_method_call_chain_wrap = on_every_item ij_kotlin_method_parameters_new_line_after_left_paren = true ij_kotlin_method_parameters_right_paren_on_new_line = false ij_kotlin_method_parameters_wrap = on_every_item ij_kotlin_name_count_to_use_star_import = 5 ij_kotlin_name_count_to_use_star_import_for_members = 3 ij_kotlin_parameter_annotation_wrap = on_every_item ij_kotlin_space_after_comma = true ij_kotlin_space_after_extend_colon = true ij_kotlin_space_after_type_colon = true ij_kotlin_space_before_catch_parentheses = true ij_kotlin_space_before_comma = false ij_kotlin_space_before_extend_colon = true ij_kotlin_space_before_for_parentheses = true ij_kotlin_space_before_if_parentheses = true ij_kotlin_space_before_lambda_arrow = true ij_kotlin_space_before_type_colon = false ij_kotlin_space_before_when_parentheses = true ij_kotlin_space_before_while_parentheses = true ij_kotlin_spaces_around_additive_operators = true ij_kotlin_spaces_around_assignment_operators = true ij_kotlin_spaces_around_equality_operators = true ij_kotlin_spaces_around_function_type_arrow = true ij_kotlin_spaces_around_logical_operators = true ij_kotlin_spaces_around_multiplicative_operators = true ij_kotlin_spaces_around_range = false ij_kotlin_spaces_around_relational_operators = true ij_kotlin_spaces_around_unary_operator = false ij_kotlin_spaces_around_when_arrow = true ij_kotlin_variable_annotation_wrap = off ij_kotlin_while_on_new_line = false ij_kotlin_wrap_elvis_expressions = 1 ij_kotlin_wrap_expression_body_functions = 0 ij_kotlin_wrap_first_method_in_call_chain = false [{*.htm, *.html, *.ng, *.sht, *.shtm, *.shtml}] ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 ij_html_align_attributes = true ij_html_align_text = false ij_html_attribute_wrap = normal ij_html_block_comment_at_first_column = true ij_html_do_not_align_children_of_min_lines = 0 ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot ij_html_enforce_quotes = false 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 ij_html_keep_blank_lines = 2 ij_html_keep_indents_on_empty_lines = false ij_html_keep_line_breaks = true ij_html_keep_line_breaks_in_text = true ij_html_keep_whitespaces = false ij_html_keep_whitespaces_inside = span, pre, textarea ij_html_line_comment_at_first_column = true ij_html_new_line_after_last_attribute = never ij_html_new_line_before_first_attribute = never ij_html_quote_style = double ij_html_remove_new_line_before_tags = br ij_html_space_after_tag_name = false ij_html_space_around_equality_in_attribute = false ij_html_space_inside_empty_tag = false ij_html_text_wrap = normal [{*.jsf, *.jsp, *.jspf, *.tag, *.tagf, *.xjsp}] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_jsp_jsp_prefer_comma_separated_import_list = false ij_jsp_keep_indents_on_empty_lines = false [{*.jspx, *.tagx}] indent_size = 4 tab_width = 4 ij_continuation_indent_size = 8 ij_jspx_keep_indents_on_empty_lines = false [{*.properties, spring.handlers, spring.schemas}] ij_properties_align_group_field_declarations = false ij_properties_keep_blank_lines = false ij_properties_key_value_delimiter = equals ij_properties_spaces_around_key_value_delimiter = false [{*.yaml, *.yml}] ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true ================================================ FILE: .gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Maven template target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties # https://github.com/takari/maven-wrapper#usage-without-binary-jar .mvn/wrapper/maven-wrapper.jar ### Linux template *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ### Windows template # Windows thumbnail cache files Thumbs.db Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf .idea/** # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries *.iml # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/artifacts # .idea/compiler.xml # .idea/jarRepositories.xml # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### macOS template # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### Java template # Compiled class file *.class # Log file *.log # BlueJ files *.ctxt # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.nar *.ear *.zip *.tar.gz *.rar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 Simplix Softworks Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

# Cirrus [![Build Status](http://ci.exceptionflug.de/buildStatus/icon?job=Cirrus)](http://ci.exceptionflug.de/job/Cirrus/) [![JetBrains IntelliJ Plugins](https://img.shields.io/jetbrains/plugin/v/15194-cirrus-tooling)](https://plugins.jetbrains.com/plugin/15194-cirrus-tooling) [![Discord](https://img.shields.io/discord/752533664696369204?label=Discord)](https://discord.simplixsoft.com/) ![GitHub](https://img.shields.io/github/license/Exceptionflug/Protocolize) Menu Framework. Cirrus enables you to develop platform-independent versatile graphical menus for Spigot, BungeeCord, and Velocity! The goal of Cirrus is to aim for maximum compatibility. Cirrus had been tested on several well-known BungeeCord-Forks as well on all Spigot versions beginning from 1.16.5 till the latest release. The first-ever way of creating menus for Velocity. # WIP Cirrus is currently WIP. The documentation is invalid in parts. We will publish a stable version soon. Spigot & BungeeCord implementations will work, Velocity implementations are currently very experimental. We aim to publish documentation & production ready versions in the coming month. ## Version Current version is: - Stable: 2.0.0 - Development: 2.1.0-SNAPHOT ## PR If you have any improvements regarding Cirrus feel free to create a PR. We are happy to review & merge it. Keep in mind that to use our codestyle as defined in .editorconfig. ## Platforms On Spigot Cirrus is fully independent of third party plugins. Protocolize is needed only only if Cirrus is used on proxies like BungeeCord or Velocity. - Spigot - BungeeCord - Velocity (WIP) ## Supported Bukkit Versions Due to the changes in the API we only officially support 1.16.5-LATEST (which is 1.19 by the time this is written) Since Cirrus is designed to be mostly version independent, older versions will likely function as well but they are deprecated (so we won't attempt to resolve issues with these versions). ## Tooling Cirrus offers an IntelliJ plugin to enhance the usability of Cirrus. It provides a realtime preview while editing menu configuration files. [![JetBrains IntelliJ plugins](https://img.shields.io/jetbrains/plugin/d/15194-cirrus-tooling)](https://plugins.jetbrains.com/plugin/15194-cirrus-tooling) ![Tooling](https://i.imgur.com/88pvZ8G.gif) ## Requirements ### Protocolize Cirrus is powered by [Protocolize](https://github.com/Exceptionflug/protocolize). A protocol manipulation library by one of the Simplix Softworks founders, Exceptionflug. Protocolize enables you to do so much more on BungeeCord/Velocity! ## Installation Just shade and relocate the platform module into your own plugin. Don't forget to call the `CirrusSpigot` , `CirrusBungeeCord` or `CirrusVelocity` init method. ### More developer documentation Check out the [wiki](https://github.com/Simplix-Softworks/Cirrus/wiki) for further information on how to use Cirrus in your application. ================================================ FILE: cirrus-bungeecord/pom.xml ================================================ cirrus-bungeecord 4.0.0 cirrus dev.simplix.cirrus 2.0.0 ${cirrus.version} cirrus-common dev.simplix.cirrus compile ${cirrus.version} net.md-5 bungeecord-api 1.21-R0.1-SNAPSHOT provided ${project.name}-${project.version} src/main/resources true org.apache.maven.plugins maven-shade-plugin 3.0.0 package shade false org.apache.maven.plugins maven-compiler-plugin 8 8 org.apache.maven.plugins maven-source-plugin 3.0.1 attach-sources deploy jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.0.1 attach-javadocs jar ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/BungeeCordPlayerWrapper.java ================================================ package dev.simplix.cirrus.bungeecord; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.player.ProtocolizePlayer; import lombok.NonNull; import net.md_5.bungee.api.connection.ProxiedPlayer; import java.util.UUID; public class BungeeCordPlayerWrapper implements PlayerWrapper { private final ProtocolizePlayer protocolizePlayer; private final ProxiedPlayer handle; public BungeeCordPlayerWrapper(@NonNull ProxiedPlayer handle) { this.handle = handle; this.protocolizePlayer = Protocolize.playerProvider().player(handle.getUniqueId()); } @Override public UUID uniqueId() { return this.handle.getUniqueId(); } @Override public String name() { return this.handle.getName(); } @Override public int protocolVersion() { return this.protocolizePlayer.protocolVersion(); } @Override public void sendMessage(@NonNull String msg) { this.handle.sendMessage(msg); } @Override public void closeInventory() { this.protocolizePlayer.closeInventory(); } @Override public boolean hasPermission(@NonNull String permission) { return this.handle.hasPermission(permission); } @Override public T handle() { return (T) this.handle; } public ProtocolizePlayer protocolizePlayer() { return this.protocolizePlayer; } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/CirrusBungeeCord.java ================================================ package dev.simplix.cirrus.bungeecord; import dev.simplix.cirrus.bungeecord.converters.ItemModelConverter; import dev.simplix.cirrus.bungeecord.converters.ItemStackConverter; import dev.simplix.cirrus.bungeecord.converters.PlayerConverter; import dev.simplix.cirrus.bungeecord.converters.PlayerUniqueIdConverter; import dev.simplix.cirrus.bungeecord.listeners.QuitListener; import dev.simplix.cirrus.bungeecord.protocolize.ProtocolizeMenuBuilder; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.effect.MenuAnimator; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.protocolize.api.item.ItemStack; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import java.util.UUID; import java.util.concurrent.TimeUnit; public class CirrusBungeeCord { private static Plugin plugin; static { // Players Converters.register(ProxiedPlayer.class, PlayerWrapper.class, new PlayerConverter()); Converters.register(UUID.class, PlayerWrapper.class, new PlayerUniqueIdConverter()); // Items Converters.register(ItemStack.class, MenuItemWrapper.class, new ItemStackConverter()); Converters.register(CirrusItem.class, InventoryMenuItemWrapper.class, new ItemModelConverter()); } public static void init(Plugin plugin) { if (CirrusBungeeCord.plugin != null) { return; } CirrusBungeeCord.plugin = plugin; Cirrus.registerService(MenuBuilder.class, new ProtocolizeMenuBuilder()); ProxyServer.getInstance().getPluginManager().registerListener(plugin, new QuitListener()); ProxyServer.getInstance().getScheduler().schedule(plugin, () -> { if (ProxyServer.getInstance().getOnlineCount() > 0 && !MenuAnimator.isEmpty()) { MenuAnimator.updateAll(); } }, 50 * 2, TimeUnit.MILLISECONDS); } public static Plugin plugin() { if (plugin == null) { throw new IllegalStateException("Cirrus is not initialized. Please call CirrusBungeeCord#init during onEnable."); } // ➤ return plugin; } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/converters/ItemModelConverter.java ================================================ package dev.simplix.cirrus.bungeecord.converters; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.protocolize.api.chat.ChatElement; import dev.simplix.protocolize.api.item.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.stream.Collectors; public class ItemModelConverter implements Converter { @Override public InventoryMenuItemWrapper convert(@NotNull CirrusItem model) { ItemStack itemStack = new ItemStack(model.itemType(), model.amount(), model.durability()); itemStack.nbtData(model.nbt()); itemStack.displayName(ChatElement.ofLegacyText(model.displayName())); itemStack.lore(model.lore().stream().map(ChatElement::ofLegacyText).collect(Collectors.toList())); return InventoryMenuItemWrapper.builder() .handle(Converters.convert(itemStack, MenuItemWrapper.class)) .actionArguments(model.actionArguments()) .actionHandler(model.actionHandler()) .build(); } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/converters/ItemStackConverter.java ================================================ package dev.simplix.cirrus.bungeecord.converters; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.item.ProtocolizeMenuItemWrapper; import dev.simplix.protocolize.api.item.ItemStack; import lombok.NonNull; public class ItemStackConverter implements Converter { @Override public MenuItemWrapper convert(@NonNull ItemStack itemStack) { return new ProtocolizeMenuItemWrapper(itemStack); } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/converters/PlayerConverter.java ================================================ package dev.simplix.cirrus.bungeecord.converters; import dev.simplix.cirrus.bungeecord.BungeeCordPlayerWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converter; import lombok.NonNull; import net.md_5.bungee.api.connection.ProxiedPlayer; import org.jetbrains.annotations.NotNull; public final class PlayerConverter implements Converter { @Override public PlayerWrapper convert(@NonNull @NotNull ProxiedPlayer proxiedPlayer) { return new BungeeCordPlayerWrapper(proxiedPlayer); } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/converters/PlayerUniqueIdConverter.java ================================================ package dev.simplix.cirrus.bungeecord.converters; import dev.simplix.cirrus.bungeecord.BungeeCordPlayerWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converter; import lombok.NonNull; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import java.util.UUID; public class PlayerUniqueIdConverter implements Converter { @Override public PlayerWrapper convert(@NonNull UUID uuid) { ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid); if (player == null) { throw new IllegalArgumentException("Player " + uuid + " is offline"); } return new BungeeCordPlayerWrapper(player); } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/listeners/QuitListener.java ================================================ package dev.simplix.cirrus.bungeecord.listeners; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.menu.MenuBuilder; import lombok.NonNull; import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; public class QuitListener implements Listener { @EventHandler public void onQuit(@NonNull PlayerDisconnectEvent event) { Cirrus.getService(MenuBuilder.class).destroyMenusOfPlayer(event.getPlayer().getUniqueId()); } } ================================================ FILE: cirrus-bungeecord/src/main/java/dev/simplix/cirrus/bungeecord/protocolize/ProtocolizeMenuBuilder.java ================================================ package dev.simplix.cirrus.bungeecord.protocolize; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import dev.simplix.cirrus.bungeecord.BungeeCordPlayerWrapper; import dev.simplix.cirrus.common.Utils; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.i18n.Replacer; import dev.simplix.cirrus.common.menu.AbstractMenu; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.model.Click; import dev.simplix.protocolize.api.ClickType; import dev.simplix.protocolize.api.chat.ChatElement; import dev.simplix.protocolize.api.inventory.Inventory; import dev.simplix.protocolize.api.item.BaseItemStack; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.api.player.ProtocolizePlayer; import dev.simplix.protocolize.data.packets.OpenWindow; import dev.simplix.protocolize.data.packets.WindowItems; import lombok.NonNull; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.chat.ComponentSerializer; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; public class ProtocolizeMenuBuilder implements MenuBuilder { private final Map> buildMap = new LinkedHashMap<>(); private final Set menus = Sets.newConcurrentHashSet(); @Override public T build(@Nullable T prebuild, @NonNull Menu menu) { final Entry menuLongEntry = this.buildMap.get(menu.player().uniqueId()); if (menuLongEntry != null && !menuLongEntry.getKey().equals(menu)) { menuLongEntry.getKey().handleClose(true); } if (!(menu instanceof AbstractMenu)) { throw new IllegalArgumentException("This implementation can only build cirrus menus!"); } final boolean register = prebuild == null; if (prebuild instanceof Inventory) { String title = Replacer.of(menu.title()).replaceAll((Object[]) menu.replacements().get()) .replacedMessageJoined(); final Inventory inventory = (Inventory) prebuild; final BaseComponent[] component = TextComponent.fromLegacyText(title); for (BaseComponent baseComponent : component) { baseComponent.setItalic(false); // Wir kommen nicht aus Italien } if (!ComponentSerializer.toString((BaseComponent[]) inventory.title().asComponent()) .equals(ComponentSerializer.toString(component)) || inventory.type().getTypicalSize(menu.player().protocolVersion()) != menu .topContainer() .capacity() || inventory.type() != menu.inventoryType()) { prebuild = (T) makeInv(menu); } } else { prebuild = (T) makeInv(menu); } final Inventory inventory = (Inventory) prebuild; buildContainer(inventory, menu.topContainer()); buildContainer(inventory, menu.bottomContainer()); this.buildMap.put( menu.player().uniqueId(), new AbstractMap.SimpleEntry<>(menu, System.currentTimeMillis())); if (register) { this.menus.add(menu); } open(menu.player(), inventory); return prebuild; } private void buildContainer(@NonNull Inventory inventory, @NonNull Container container) { for (int i = container.baseSlot(); i < container.baseSlot() + container.capacity(); i++) { InventoryMenuItemWrapper item = container.itemMap().get(i); BaseItemStack currentStack = inventory.item(i); if (item == null) { if (currentStack != null) { inventory.item(i, ItemStack.NO_DATA); } } if (item != null) { for (BaseComponent[] loreComponent : item.loreComponents()) { for (BaseComponent baseComponent : loreComponent) { // if (!baseComponent.isItalic()) { // baseComponent.setItalic(false); // } } } if (currentStack == null) { if (item.handle() == null) { ProxyServer.getInstance().getLogger() .severe("InventoryItem's ItemStackWrapper is null @ slot " + i); continue; } inventory.item(i, item.handle()); } else { if (!currentStack.equals(item.handle())) { inventory.item(i, item.handle()); } } } } } private Inventory makeInv(@NonNull Menu menu) { Inventory inventory = new Inventory(menu.inventoryType()); BaseComponent[] textComponent = TextComponent.fromLegacyText(Replacer.of(menu.title()) .replaceAll((Object[]) menu.replacements().get()).replacedMessageJoined()); for (BaseComponent component : textComponent) { if (!component.isItalic()) { component.setItalic(false); // Resolve client side behavior } } inventory.title(ChatElement.of(textComponent)); inventory.onClose(inventoryClose -> { Map.Entry lastBuild = lastBuildOfPlayer(inventoryClose.player().uniqueId()); if (((AbstractMenu) lastBuild.getKey()).internalId() == ((AbstractMenu) menu).internalId() && (System.currentTimeMillis() - lastBuild.getValue()) <= 55) { return; } menu.handleClose((System.currentTimeMillis() - lastBuild.getValue()) <= 55); invalidate(menu); }); inventory.onClick(inventoryClick -> { if (inventoryClick.clickType() == null) { return; } if (inventoryClick.player() == null) { return; } Inventory i = inventoryClick.inventory(); if (i == null) { return; } // ProxyServer.getInstance().broadcast("Clicked inventory"); // ProxyServer.getInstance().broadcast("Clicked menu: " + menu.getClass().getSimpleName() + " @ slot " + inventoryClick.slot()); Container container; if (inventoryClick.slot() > menu.topContainer().capacity() - 1) { container = menu.bottomContainer(); // ProxyServer.getInstance().broadcast("Clicked bottom container"); } else { container = menu.topContainer(); // ProxyServer.getInstance().broadcast("Clicked top container"); } InventoryMenuItemWrapper item = container.get(inventoryClick.slot()); ClickType type = inventoryClick.clickType(); if (item == null) { // ProxyServer.getInstance().broadcast("Clicked nothing"); if (menu.customActionHandler() != null) { try { CallResult callResult = menu .customActionHandler() .handle(new Click(type, menu, null, inventoryClick.slot())); inventoryClick.cancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (Exception ex) { inventoryClick.cancelled(true); menu.handleException(null, ex); } } return; } // ProxyServer.getInstance().broadcast("Clicked " + item.displayName()); ActionHandler actionHandler = menu.actionHandler(item.actionHandler()); if (actionHandler == null) { inventoryClick.cancelled(true); return; } try { final CallResult callResult = actionHandler.handle(new Click( type, menu, item, inventoryClick.slot())); inventoryClick.cancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (final Exception ex) { inventoryClick.cancelled(true); menu.handleException(actionHandler, ex); } }); return inventory; } @Override public void open( PlayerWrapper playerWrapper, T inventoryImpl) { if (playerWrapper instanceof BungeeCordPlayerWrapper) { final ProtocolizePlayer protocolizePlayer = ((BungeeCordPlayerWrapper) playerWrapper).protocolizePlayer(); final Inventory inventory = (Inventory) inventoryImpl; boolean alreadyOpen = false; int windowId = -1; for (Integer id : protocolizePlayer.registeredInventories().keySet()) { Inventory val = protocolizePlayer.registeredInventories().get(id); if (val.type() == inventory.type() && val.title().equals(inventory.title())) { alreadyOpen = true; break; } } // Close all inventories if not opened if (!alreadyOpen) { protocolizePlayer.closeInventory(); } if (protocolizePlayer.registeredInventories().containsValue(inventory)) { for (Integer id : protocolizePlayer.registeredInventories().keySet()) { Inventory val = protocolizePlayer.registeredInventories().get(id); if (val == inventory) { windowId = id; break; } } if (windowId == -1) { windowId = protocolizePlayer.generateWindowId(); protocolizePlayer.registerInventory(windowId, inventory); } } else { windowId = protocolizePlayer.generateWindowId(); protocolizePlayer.registerInventory(windowId, inventory); } if (!alreadyOpen) { protocolizePlayer.sendPacket(new OpenWindow(windowId, inventory.type(), inventory.title())); } int protocolVersion; try { protocolVersion = protocolizePlayer.protocolVersion(); } catch (Throwable t) { protocolVersion = 47; } List items = Lists.newArrayList(inventory.itemsIndexed(protocolVersion)); protocolizePlayer.sendPacket(new WindowItems((short) windowId, items, 0)); } } private void removeItalic(BaseComponent[] components) { for (BaseComponent component : components) { component.setItalic(false); } } @Override @Nullable public Menu menuByHandle(Object handle) { if (handle == null) { return null; } for (final Menu menu : this.menus) { if (menu.equals(handle)) { return menu; } } return null; } @Override public void destroyMenusOfPlayer(@NonNull UUID uniqueId) { this.menus.removeIf( wrapper -> ((ProxiedPlayer) wrapper.player().handle()).getUniqueId().equals(uniqueId)); this.buildMap.remove(uniqueId); } @Override public Entry lastBuildOfPlayer(@NonNull UUID uniqueId) { return this.buildMap.get(uniqueId); } @Override public void invalidate(@NonNull Menu menu) { this.menus.remove(menu); } } ================================================ FILE: cirrus-bungeecord-example/pom.xml ================================================ 4.0.0 dev.simplix.cirrus cirrus 2.0.0 dev.simplix.cirrus cirrus-bungeecord-example ${cirrus.version} cirrus-common dev.simplix.cirrus compile ${cirrus.version} cirrus-bungeecord dev.simplix.cirrus compile ${cirrus.version} net.md-5 bungeecord-api 1.21-R0.1-SNAPSHOT provided ${project.name}-${project.version} src/main/resources true org.apache.maven.plugins maven-shade-plugin 3.0.0 package shade org.apache.maven.plugins maven-compiler-plugin 8 8 ================================================ FILE: cirrus-bungeecord-example/src/main/java/dev/simplix/cirrus/bungeecord/example/CirrusExamplePlugin.java ================================================ package dev.simplix.cirrus.bungeecord.example; import dev.simplix.cirrus.bungeecord.CirrusBungeeCord; import dev.simplix.cirrus.bungeecord.example.commands.TestCommand; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.plugin.Plugin; public class CirrusExamplePlugin extends Plugin { @Override public void onEnable() { CirrusBungeeCord.init(this); ProxyServer.getInstance().getPluginManager().registerCommand(this, new TestCommand()); } } ================================================ FILE: cirrus-bungeecord-example/src/main/java/dev/simplix/cirrus/bungeecord/example/commands/TestCommand.java ================================================ package dev.simplix.cirrus.bungeecord.example.commands; import dev.simplix.cirrus.bungeecord.example.menus.ExampleMenu; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converters; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Command; public class TestCommand extends Command { public TestCommand() { super("test"); } @Override public void execute(CommandSender sender, String[] args) { if (sender instanceof ProxiedPlayer) { ProxiedPlayer proxy = (ProxiedPlayer) sender; new ExampleMenu(Converters.convert(proxy, PlayerWrapper.class), Cirrus.configurationFactory().loadFile("plugins/Cirrus/example.json")).open(); } } } ================================================ FILE: cirrus-bungeecord-example/src/main/java/dev/simplix/cirrus/bungeecord/example/menus/ExampleMenu.java ================================================ package dev.simplix.cirrus.bungeecord.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.menu.AbstractConfigurableMenu; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import java.util.Locale; public class ExampleMenu extends AbstractConfigurableMenu { public ExampleMenu(PlayerWrapper player, MenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerActionHandler("tnt", click -> { topContainer().itemMap().remove(click.slot()); title("Hello, {viewer}"); build(); player().sendMessage("It simply works :)"); return CallResult.DENY_GRABBING; }); } } ================================================ FILE: cirrus-bungeecord-example/src/main/java/dev/simplix/cirrus/bungeecord/example/menus/ExampleMultiPageMenu.java ================================================ package dev.simplix.cirrus.bungeecord.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.menus.MultiPageMenu; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.api.providers.MappingProvider; import dev.simplix.protocolize.data.ItemType; import java.util.Collections; import java.util.Locale; public class ExampleMultiPageMenu extends MultiPageMenu { private final MappingProvider mappingProvider = Protocolize.mappingProvider(); public ExampleMultiPageMenu( PlayerWrapper player, MultiPageMenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerMyActionHandlers(); addItems(); } private void registerMyActionHandlers() { registerActionHandler("test", click -> { player().sendMessage("This is " + click.clickedItem().type().name()); return CallResult.DENY_GRABBING; }); } private void addItems() { for (ItemType type : ItemType.values()) { if (this.mappingProvider.mapping(type, player().protocolVersion()) != null) { add(wrapItemStack(new ItemStack(type)), "test", Collections.emptyList()); } } } } ================================================ FILE: cirrus-bungeecord-example/src/main/resources/plugin.yml ================================================ name: CirrusExample author: Exceptionflug version: 1.0 main: dev.simplix.cirrus.bungeecord.example.CirrusExamplePlugin softdepend: - simplixcore commands: test: description: hi ================================================ FILE: cirrus-common/pom.xml ================================================ cirrus-common maven-compiler-plugin 8 8 org.apache.maven.plugins org.apache.maven.plugins maven-source-plugin 3.0.1 attach-sources deploy jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.0.1 attach-javadocs jar none org.slf4j slf4j-api 1.8.0-alpha2 provided 4.0.0 cirrus dev.simplix.cirrus 2.0.0 ${cirrus.version} ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/Cirrus.java ================================================ package dev.simplix.cirrus.common; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import dev.simplix.cirrus.common.business.ConfigurationFactory; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.config.JsonConfigurationFactory; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.i18n.*; import dev.simplix.cirrus.common.mojangson.TagDeserializer; import dev.simplix.cirrus.common.mojangson.TagSerializer; import net.querz.nbt.tag.CompoundTag; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Cirrus { private static final Map, Object> SERVICES = new ConcurrentHashMap<>(); public static Gson gson() { return GSON; } private static final Gson GSON = new GsonBuilder() .registerTypeAdapter(CompoundTag.class, new TagSerializer()) .registerTypeAdapter(CompoundTag.class, new TagDeserializer()) .registerTypeAdapter(LocalizedString.class, new LocalizedStringSerializer()) .registerTypeAdapter(LocalizedString.class, new LocalizedStringDeserializer()) .registerTypeAdapter(LocalizedStringList.class, new LocalizedStringListSerializer()) .registerTypeAdapter(LocalizedStringList.class, new LocalizedStringListDeserializer()) .setPrettyPrinting() .create(); static { Converters.register( InventoryMenuItemWrapper.class, MenuItemWrapper.class, (Converter) InventoryMenuItemWrapper::wrapper); registerService(ConfigurationFactory.class, new JsonConfigurationFactory(GSON)); } /** * This returns an instance of a registered service. * * @param type The registration type of the desired service * @param The type of the service * @return The instance of T or null if there is no service with this registration type * @see Cirrus#registerService(Class, Object) */ public static T getService(Class type) { return (T) SERVICES.get(type); } /** * This will map a given service instance to a given registration type. * * @param type The registration type of the desired service * @param instance An instance of the registration type * @param The registration type */ public static void registerService(Class type, T instance) { SERVICES.put(type, instance); } public static ConfigurationFactory configurationFactory() { return getService(ConfigurationFactory.class); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/Utils.java ================================================ package dev.simplix.cirrus.common; import lombok.experimental.UtilityClass; import net.md_5.bungee.api.chat.BaseComponent; import net.querz.nbt.tag.*; @UtilityClass public class Utils { private static final String STEVE_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTU5MTU3NDcyMzc4MywKICAicHJvZmlsZUlkIiA6ICI4NjY3YmE3MWI4NWE0MDA0YWY1NDQ1N2E5NzM0ZWVkNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJTdGV2ZSIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82ZDNiMDZjMzg1MDRmZmMwMjI5Yjk0OTIxNDdjNjlmY2Y1OWZkMmVkNzg4NWY3ODUwMjE1MmY3N2I0ZDUwZGUxIgogICAgfSwKICAgICJDQVBFIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS85NTNjYWM4Yjc3OWZlNDEzODNlNjc1ZWUyYjg2MDcxYTcxNjU4ZjIxODBmNTZmYmNlOGFhMzE1ZWE3MGUyZWQ2IgogICAgfQogIH0KfQ=="; public void removeItalic(BaseComponent[] components) { for (BaseComponent component : components) { component.setItalic(false); } } public static void hideNbtFlags(CompoundTag tag) { tag.put("HideFlags", new IntTag(127)); } public static void glow(CompoundTag tag) { hideNbtFlags(tag); final ListTag enchantments = new ListTag<>(CompoundTag.class); final ListTag enchs = new ListTag<>(CompoundTag.class); final CompoundTag exampleEnchantment = new CompoundTag(); exampleEnchantment.put("id", new StringTag("minecraft:efficiency")); exampleEnchantment.put("lvl", new ShortTag((short) 1)); final CompoundTag exampleEnch = new CompoundTag(); exampleEnch.put("id", new ShortTag((short) 1)); exampleEnch.put("lvl", new ShortTag((short) 1)); enchantments.add(exampleEnchantment); enchs.add(exampleEnch); tag.put("ench", enchs); tag.put("Enchantments", enchantments); } public static void texture(CompoundTag tag, String textureHash) { if (!(tag.get("SkullOwner") instanceof CompoundTag)) { tag.put("SkullOwner", new CompoundTag()); } CompoundTag skullOwner = tag.getCompoundTag("SkullOwner"); if (skullOwner == null) { skullOwner = new CompoundTag(); } skullOwner.put("Name", new StringTag(textureHash)); CompoundTag properties = skullOwner.getCompoundTag("Properties"); if (properties == null) { properties = new CompoundTag(); } CompoundTag texture = new CompoundTag(); texture.put( "Value", new StringTag(textureHash.isEmpty() ? STEVE_TEXTURE : textureHash)); ListTag textures = new ListTag<>(CompoundTag.class); textures.add(texture); properties.put("textures", textures); skullOwner.put("Properties", properties); tag.put("SkullOwner", skullOwner); } public static int calculateSizeForContent(final int items) { return ( items <= 9 ? 9 * 1 : items <= 9 * 2 ? 9 * 2 : items <= 9 * 3 ? 9 * 3 : items <= 9 * 4 ? 9 * 4 : 9 * 5) + 9; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/business/ConfigurationFactory.java ================================================ package dev.simplix.cirrus.common.business; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.configuration.impl.SimpleMenuConfiguration; import dev.simplix.cirrus.common.configuration.impl.SimpleMultiPageMenuConfiguration; import lombok.NonNull; public interface ConfigurationFactory { default MenuConfiguration loadFile(@NonNull String file) { return loadFile(file, SimpleMenuConfiguration.class); } default MenuConfiguration loadResource(@NonNull String resourcePath, @NonNull Class caller) { return loadResource(resourcePath, caller, SimpleMenuConfiguration.class); } default MultiPageMenuConfiguration loadFileForMultiPageMenu(@NonNull String file) { return loadFile(file, SimpleMultiPageMenuConfiguration.class); } default MultiPageMenuConfiguration loadResourcesForMultiPageMenu( @NonNull String resourcePath, @NonNull Class caller) { return loadResource(resourcePath, caller, SimpleMultiPageMenuConfiguration.class); } T loadFile(@NonNull String file, @NonNull Class type); T loadResource( @NonNull String resourcePath, @NonNull Class caller, @NonNull Class type); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/business/DataInventoryMenuItemWrapper.java ================================================ package dev.simplix.cirrus.common.business; import lombok.Getter; import lombok.NonNull; import lombok.ToString; import lombok.experimental.Accessors; import java.util.List; @Accessors(fluent = true) @Getter @ToString(callSuper = true) public class DataInventoryMenuItemWrapper extends InventoryMenuItemWrapper { private final T data; public DataInventoryMenuItemWrapper( @NonNull MenuItemWrapper handle, @NonNull String actionHandler, @NonNull List actionArguments, T data) { super(handle, actionHandler, actionArguments); this.data = data; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/business/InventoryMenuItemWrapper.java ================================================ package dev.simplix.cirrus.common.business; import dev.simplix.protocolize.data.ItemType; import lombok.Builder; import lombok.Getter; import lombok.NonNull; import lombok.Setter; import lombok.experimental.Accessors; import net.md_5.bungee.api.chat.BaseComponent; import net.querz.nbt.tag.CompoundTag; import java.util.List; @Accessors(fluent = true) @Builder public class InventoryMenuItemWrapper implements MenuItemWrapper { private final MenuItemWrapper handle; @Getter @Setter private String actionHandler; @Getter @Setter private List actionArguments; @Override public String displayName() { return this.handle.displayName(); } @Override public BaseComponent[] displayNameComponents() { return this.handle.displayNameComponents(); } @Override public List lore() { return this.handle.lore(); } @Override public List loreComponents() { return this.handle.loreComponents(); } @Override public ItemType type() { return this.handle.type(); } @Override public CompoundTag nbt() { return this.handle.nbt(); } @Override public int amount() { return this.handle.amount(); } @Override public short durability() { return this.handle.durability(); } @Override public void type(@NonNull ItemType type) { this.handle.type(type); } @Override public void displayName(@NonNull String displayName) { this.handle.displayName(displayName); } @Override public void displayNameComponents(@NonNull BaseComponent... baseComponents) { this.handle.displayNameComponents(baseComponents); } @Override public void lore(@NonNull List lore) { this.handle.lore(lore); } @Override public void loreComponents(@NonNull List lore) { this.handle.loreComponents(lore); } @Override public void nbt(@NonNull CompoundTag tag) { this.handle.nbt(tag); } @Override public void amount(int amount) { this.handle.amount(amount); } @Override public void durability(short durability) { this.handle.durability(durability); } @Override public T handle() { return this.handle.handle(); } public MenuItemWrapper wrapper() { return this.handle; } @Override public String toString() { return "InventoryItemWrapper{" + "handle=" + this.handle + ", actionHandler='" + this.actionHandler + '\'' + ", actionArguments=" + this.actionArguments + '}'; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/business/MenuItemWrapper.java ================================================ package dev.simplix.cirrus.common.business; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import net.md_5.bungee.api.chat.BaseComponent; import net.querz.nbt.tag.CompoundTag; import java.util.List; /** * An {@link MenuItemWrapper} provides uniform data access for items across different platforms. * Please be aware, that most of the given properties are immutable, so you have to set them using * their setter after you have done some changes. */ public interface MenuItemWrapper { /** * Returns the display name of an item as a string. * * @return display name */ String displayName(); /** * Returns the display name of an item as component array. * * @return display name */ BaseComponent[] displayNameComponents(); /** * The lore of the item as strings. * * @return lore */ List lore(); /** * The lore of the item as component arrays. * * @return lore */ List loreComponents(); /** * The {@link ItemType} of the item. * * @return item type */ ItemType type(); /** * This returns a querz-nbt {@link CompoundTag} with the nbt information about this item. Please * be aware, that the nbt data of spigot ItemStacks are immutable. So you have to call setNBT() * after you changed the data to set them. * * @return nbt data */ CompoundTag nbt(); /** * Returns the amount of the stack * * @return amount */ int amount(); /** * Returns the durability of the item. * * @return */ short durability(); /** * Sets the mcc item type. * * @param type type to set */ void type(@NonNull ItemType type); /** * Sets the display name of the item * * @param displayName name */ void displayName(@NonNull String displayName); /** * Sets the display name of the item * * @param baseComponents name */ void displayNameComponents(@NonNull BaseComponent... baseComponents); /** * Sets the lore of the item * * @param lore */ void lore(List lore); /** * Sets the lore of the item * * @param lore */ void loreComponents(@NonNull List lore); /** * Sets the nbt data. * * @param tag nbt data */ void nbt(@NonNull CompoundTag tag); /** * Sets the stack amount. * * @param amount amount */ void amount(int amount); /** * Sets the durability. *
#DUDELAVERITY * * @param durability durability */ void durability(short durability); /** * Returns the handle of the wrapper * * @param dyncast handle type * @return the handle */ T handle(); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/business/PlayerWrapper.java ================================================ package dev.simplix.cirrus.common.business; import lombok.NonNull; import java.util.UUID; public interface PlayerWrapper { void sendMessage(@NonNull String msg); void closeInventory(); boolean hasPermission(@NonNull String permission); UUID uniqueId(); String name(); int protocolVersion(); T handle(); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/config/JsonConfigurationFactory.java ================================================ package dev.simplix.cirrus.common.config; import com.google.common.io.ByteStreams; import com.google.gson.Gson; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.ConfigurationFactory; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import lombok.NonNull; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.util.Objects; public class JsonConfigurationFactory implements ConfigurationFactory { private final Gson gson; public JsonConfigurationFactory(Gson gson) { this.gson = gson; } @Override public T loadFile( @NonNull String filename, @NonNull Class type) { File file = new File(filename); if (!file.exists()) { if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } copyResourceToFile("/cirrus/" + type.getSimpleName() + ".json", file); } try ( InputStreamReader reader = new InputStreamReader( Files.newInputStream(file.toPath()), StandardCharsets.UTF_8)) { return this.gson.fromJson(reader, type); } catch (IOException ioException) { throw new RuntimeException(ioException); } } @Override public T loadResource( @NonNull String resourcePath, @NonNull Class caller, @NonNull Class type) { try (InputStream stream = caller.getResourceAsStream(resourcePath)) { if (stream == null) { throw new NoSuchFileException("Unable to find resource " + resourcePath); } String contents = new String(ByteStreams.toByteArray(stream), StandardCharsets.UTF_8); return this.gson.fromJson(contents, type); } catch (IOException e) { throw new RuntimeException(e); } } private void copyResourceToFile(@NonNull String resource, @NonNull File file) { try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { fileOutputStream.write(ByteStreams.toByteArray( Objects.requireNonNull(Cirrus.class.getResourceAsStream(resource), "Inputstream is null"))); fileOutputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/configuration/MenuConfiguration.java ================================================ package dev.simplix.cirrus.common.configuration; import com.google.common.base.Preconditions; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; import dev.simplix.cirrus.common.i18n.LocalizedString; public interface MenuConfiguration { default LocalizedItemStackModel forceBusinessItem(String keyword) { return Preconditions.checkNotNull( businessItems().get(keyword), "No business-item named '" + keyword + "' found" ); } LocalizedString title(); dev.simplix.protocolize.data.inventory.InventoryType type(); LocalizedItemStackModel placeholderItem(); int[] reservedSlots(); LocalizedItemStackModel[] items(); java.util.Map businessItems(); MenuConfiguration title(LocalizedString title); MenuConfiguration type(dev.simplix.protocolize.data.inventory.InventoryType type); MenuConfiguration placeholderItem(LocalizedItemStackModel placeholderItem); MenuConfiguration reservedSlots(int[] reservedSlots); MenuConfiguration items(LocalizedItemStackModel[] items); MenuConfiguration businessItems(java.util.Map businessItems); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/configuration/MultiPageMenuConfiguration.java ================================================ package dev.simplix.cirrus.common.configuration; import dev.simplix.cirrus.common.i18n.LocalizedString; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; public interface MultiPageMenuConfiguration extends MenuConfiguration { LocalizedItemStackModel nextPageItem(); LocalizedItemStackModel previousPageItem(); MultiPageMenuConfiguration title(LocalizedString title); MultiPageMenuConfiguration type(dev.simplix.protocolize.data.inventory.InventoryType type); MultiPageMenuConfiguration placeholderItem(LocalizedItemStackModel placeholderItem); MultiPageMenuConfiguration reservedSlots(int[] reservedSlots); MultiPageMenuConfiguration items(LocalizedItemStackModel[] items); MultiPageMenuConfiguration businessItems(java.util.Map businessItems); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/configuration/impl/SimpleMenuConfiguration.java ================================================ package dev.simplix.cirrus.common.configuration.impl; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.i18n.LocalizedString; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; import dev.simplix.protocolize.data.inventory.InventoryType; import java.util.HashMap; import java.util.Map; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @Data @Accessors(fluent = true) @NoArgsConstructor public class SimpleMenuConfiguration implements MenuConfiguration { private LocalizedString title; private InventoryType type; private LocalizedItemStackModel placeholderItem; private int[] reservedSlots = new int[0]; private LocalizedItemStackModel[] items = new LocalizedItemStackModel[0]; private Map businessItems = new HashMap<>(); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/configuration/impl/SimpleMultiPageMenuConfiguration.java ================================================ package dev.simplix.cirrus.common.configuration.impl; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.i18n.LocalizedString; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; import dev.simplix.protocolize.data.inventory.InventoryType; import java.util.HashMap; import java.util.Map; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @Data @Builder @Accessors(fluent = true) @AllArgsConstructor @NoArgsConstructor public class SimpleMultiPageMenuConfiguration implements MultiPageMenuConfiguration { private LocalizedItemStackModel nextPageItem; private LocalizedItemStackModel previousPageItem; private LocalizedString title; private InventoryType type; private LocalizedItemStackModel placeholderItem; private int[] reservedSlots = new int[0]; private LocalizedItemStackModel[] items = new LocalizedItemStackModel[0]; private Map businessItems = new HashMap<>(); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/container/Container.java ================================================ package dev.simplix.cirrus.common.container; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.item.CirrusItem; import java.util.List; import java.util.Map; import java.util.Set; /** * A container stores {@link InventoryMenuItemWrapper}s at a given slot position. */ public interface Container { /** * Returns a map collecting all items. * * @return The map */ Map itemMap(); /** * Returns a set with slots that are marked as reserved * * @return The set */ Set reservedSlots(); /** * Returns the maximum capacity of this container * * @return the maximum amount of items this container can hold */ int capacity(); /** * Returns the initial slot id of this container * * @return Initial slot id */ int baseSlot(); /** * @return the slot index of the next available empty slot or -1 if no slot is empty */ int nextFreeSlot(); /** * @return the slot index of the next available empty slot or -1 after the specified index */ int nextFreeSlot(int i); /** * Sets an item into the next free slot. Free slots are slots where no item has been set and the * slot is not marked as reserved. * * @param inventoryItemWrapper The item to set */ default void add(InventoryMenuItemWrapper inventoryItemWrapper) { set(nextFreeSlot(), inventoryItemWrapper); } /** * Sets an item into the next free slot. Free slots are slots where no item has been set and the * slot is not marked as reserved. * * @param menuItemWrapper The item stack to set * @param actionHandler The action handler which should be called on click * @param actionArgs the arguments for that click */ default void add( MenuItemWrapper menuItemWrapper, String actionHandler, List actionArgs) { set(nextFreeSlot(), InventoryMenuItemWrapper.builder() .handle(menuItemWrapper) .actionHandler(actionHandler) .actionArguments(actionArgs) .build()); } /** * Sets an item into the next free slot. Free slots are slots where no item has been set and the * slot is not marked as reserved. * * @param model The item stack model */ default void add(CirrusItem model) { set(nextFreeSlot(), InventoryMenuItemWrapper.builder() .handle(Converters.convert(model, InventoryMenuItemWrapper.class)) .actionHandler(model.actionHandler()) .actionArguments(model.actionArguments()) .build()); } /** * Sets an item into a given position in the container * * @param slot The slot the item will be located at * @param inventoryItemWrapper The item stack wrapper */ default void set(int slot, InventoryMenuItemWrapper inventoryItemWrapper) { itemMap().put(slot, inventoryItemWrapper); } /** * Sets an item into a given position in the container * * @param slot The slot the item will be located at * @param menuItemWrapper The item stack wrapper * @param actionHandler The handler that handles the click * @param actionArgs Arguments for the action handler */ default void set( int slot, MenuItemWrapper menuItemWrapper, String actionHandler, List actionArgs) { set(slot, InventoryMenuItemWrapper.builder() .handle(menuItemWrapper) .actionHandler(actionHandler) .actionArguments(actionArgs) .build()); } /** * Sets an item into a given position in the container * * @param slot The slot the item will be located at * @param model The item stack model */ default void set(int slot, CirrusItem model) { set(slot, InventoryMenuItemWrapper.builder() .handle(Converters.convert(model, InventoryMenuItemWrapper.class)) .actionHandler(model.actionHandler()) .actionArguments(model.actionArguments()) .build()); } /** * Returns the item stack from the given position * * @param slot slot * @return item */ default InventoryMenuItemWrapper get(int slot) { return itemMap().get(slot); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/container/impl/ItemContainer.java ================================================ package dev.simplix.cirrus.common.container.impl; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.util.InventoryContentMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import lombok.NonNull; public class ItemContainer implements Container { private final InventoryContentMap inventoryContentMap = new InventoryContentMap(); private final Set reservedSlots = new HashSet<>(); private final int baseSlotIndex; private final int capacity; public ItemContainer(int baseSlotIndex, int capacity) { this.baseSlotIndex = baseSlotIndex; this.capacity = capacity; } @Override public void set(int slot, @NonNull InventoryMenuItemWrapper inventoryItemWrapper) { itemMap().put(slot + this.baseSlotIndex, inventoryItemWrapper); } @Override public Map itemMap() { return this.inventoryContentMap; } @Override public Set reservedSlots() { return this.reservedSlots; } @Override public int capacity() { return this.capacity; } @Override public int baseSlot() { return this.baseSlotIndex; } @Override public int nextFreeSlot() { for (int i = this.baseSlotIndex; i < this.capacity + this.baseSlotIndex; i++) { if (!itemMap().containsKey(i) && !reservedSlots().contains(i)) { return i; } } return -1; } @Override public int nextFreeSlot(int base) { for (int i = base; i < this.capacity + this.baseSlotIndex; i++) { if (!itemMap().containsKey(i) && !reservedSlots().contains(i)) { return i; } } return -1; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/converter/Converter.java ================================================ package dev.simplix.cirrus.common.converter; import lombok.NonNull; /** * A converter is used to convert one object to another. * * @param The source type of the object * @param The target type ot the object */ public interface Converter { /** * Converts a given source object to the target type. * * @param src The source object * @return The target object */ Target convert(@NonNull Source src); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/converter/Converters.java ================================================ package dev.simplix.cirrus.common.converter; import lombok.NonNull; import org.jetbrains.annotations.Nullable; import java.util.AbstractMap.SimpleEntry; import java.util.*; import java.util.Map.Entry; /** * Central registration class for {@link Converter}s. */ @SuppressWarnings("rawtypes") public final class Converters { private static final Map, Converter> CONVERTER_MAP = new HashMap<>(); private Converters() { } /** * Converts a source object to a given type. * * @param source The source object to convert * @param to The target type class * @param The target type * @return An object instance of the target type */ public static T convert(@NonNull final Object source, @NonNull final Class to) { Converter converter = getConverter(source.getClass(), to); if (converter == null) { converter = getMultiConverter(source.getClass(), to); } if (converter == null) { throw new NullPointerException("No converter available to convert " + source .getClass() .getName() + " to " + to.getName()); } return (T) converter.convert(source); } private static Converter getMultiConverter( @NonNull final Class source, @NonNull final Class to) { final List converters = new ArrayList<>(); findConversionRoute(converters, source, to); if (converters.size() <= 1) { return null; } return src -> { Object out = src; for (final Converter converter : converters) { out = converter.convert(out); } return (T) out; }; } private static boolean findConversionRoute( @NonNull final List converters, @NonNull final Class source, @NonNull final Class to) { for (final Entry entry : CONVERTER_MAP.keySet()) { if (entry.getKey().equals(source)) { final List list = new ArrayList<>(); if (buildRoute(list, entry, to)) { list.add(CONVERTER_MAP.get(entry)); Collections.reverse(list); converters.addAll(list); return true; } } } return false; } private static boolean buildRoute( @NonNull final List converters, @NonNull final Map.Entry entry, @NonNull final Class to) { if (entry.getValue().equals(to)) { return true; } for (final Entry entry1 : CONVERTER_MAP.keySet()) { if (entry1.getKey().equals(entry.getValue())) { if (buildRoute(converters, entry1, to)) { converters.add(CONVERTER_MAP.get(entry1)); return true; } } } return false; } /** * Registers a {@link Converter} for a given type conversion. * * @param sourceType The source type * @param targetType The target type * @param converter The convert instance */ public static void register( @NonNull final Class sourceType, @NonNull final Class targetType, @NonNull final Converter converter) { CONVERTER_MAP.put(new SimpleEntry<>(sourceType, targetType), converter); } /** * Returns a registered converter * * @param sourceType The source type class * @param targetType The target type class * @param The source type * @param The target type * @return The converter instance or null if no such converter exists */ @Nullable public static Converter getConverter( final Class sourceType, final Class targetType) { Converter converter = CONVERTER_MAP.get(new SimpleEntry<>(sourceType, targetType)); if (converter == null) { for (Entry entry : CONVERTER_MAP.keySet()) { if (entry.getKey().isAssignableFrom(sourceType)) { if (entry.getValue().equals(targetType)) { return CONVERTER_MAP.get(entry); } } } } return converter; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/AbstractChangingItemAnimation.java ================================================ package dev.simplix.cirrus.common.effect; import dev.simplix.cirrus.common.item.CirrusItem; public abstract class AbstractChangingItemAnimation extends AbstractMenuAnimation { protected AbstractChangingItemAnimation(CirrusItem input, int effectLength) { super(input, effectLength); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/AbstractMenuAnimation.java ================================================ package dev.simplix.cirrus.common.effect; import com.google.common.base.Preconditions; import com.google.common.collect.Iterators; import java.util.Iterator; public abstract class AbstractMenuAnimation implements MenuAnimation { protected final T input; protected final int effectLength; private Iterator iterator; protected AbstractMenuAnimation( T input, int effectLength) { this.input = Preconditions.checkNotNull(input, "input must not be null"); Preconditions.checkState(effectLength > 0, "effectLength is not larger than 0"); this.effectLength = effectLength; } @Override public int effectLength() { return this.effectLength; } @Override public final T input() { return this.input; } @Override public final T next() { if (this.iterator == null) { this.iterator = Iterators.cycle(calculate()); } return this.iterator.next(); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/Animated.java ================================================ package dev.simplix.cirrus.common.effect; import dev.simplix.cirrus.common.menu.Menu; public interface Animated extends Menu { void update(); @Override default void handleClose(boolean inventorySwitch) { MenuAnimator.remove(this); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/Animations.java ================================================ package dev.simplix.cirrus.common.effect; import lombok.experimental.UtilityClass; @UtilityClass public class Animations { } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/MenuAnimation.java ================================================ package dev.simplix.cirrus.common.effect; import java.util.List; public interface MenuAnimation { /** * Duration of the effect in the menu in ticks */ int effectLength(); /** * Initial input of the effect */ T input(); /** * All calculated values for the effect */ List calculate(); /** * Next effect frame. Usually calculated with an * infinite iterable calculated with {@link MenuAnimation#calculate()} * and created with {@link com.google.common.collect.Iterables#cycle(Object[])} */ T next(); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effect/MenuAnimator.java ================================================ package dev.simplix.cirrus.common.effect; import lombok.NonNull; import lombok.experimental.UtilityClass; import java.util.LinkedList; import java.util.List; @UtilityClass public class MenuAnimator { private final List menus = new LinkedList<>(); public boolean isEmpty() { return menus.isEmpty(); } public void register(@NonNull Animated menu) { menus.add(menu); } public void remove(@NonNull Animated menu) { menus.remove(menu); } public void updateAll() { for (Animated menu : menus) { menu.update(); menu.build(); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effects/GradualColorChangeAnimation.java ================================================ package dev.simplix.cirrus.common.effects; import com.google.common.base.Preconditions; import dev.simplix.cirrus.common.effect.AbstractMenuAnimation; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Will generate: ... */ public class GradualColorChangeAnimation extends AbstractMenuAnimation { protected final String primaryColor; protected final String secondaryColor; protected boolean reverse = false; protected int transitionCount = 0; public GradualColorChangeAnimation( String primaryColor, String input) { this(primaryColor, "§f§l", input, 2); } public GradualColorChangeAnimation( String primaryColor, String secondaryColor, String input, int effectLength) { super(input, effectLength); this.primaryColor = Preconditions.checkNotNull(primaryColor, "primaryColor must not be null"); this.secondaryColor = Preconditions.checkNotNull(secondaryColor, "secondaryColor must not be null"); } public GradualColorChangeAnimation reversed() { this.reverse = true; return this; } public GradualColorChangeAnimation reverse(boolean reverse) { this.reverse = reverse; return this; } public GradualColorChangeAnimation transitionCount(int transitionCount) { this.transitionCount = transitionCount; return this; } public GradualColorChangeAnimation length(int length) { return new GradualColorChangeAnimation(this.primaryColor, this.secondaryColor, this.input, length).reverse(this.reverse).transitionCount(this.transitionCount); } @Override public List calculate() { final List out = new ArrayList<>(); out.addAll(insertEffect(this.primaryColor, this.secondaryColor)); out.addAll(insertEffect(this.secondaryColor, this.primaryColor)); return out; } private List insertEffect(String effectColor, String primaryColor) { final List out = new ArrayList<>(); if (this.reverse) { for (int i = this.input.length() - 1; i >= 0; i--) { out.addAll(Collections.nCopies(this.effectLength, addAtIndex(primaryColor + this.input, effectColor, i + primaryColor.length()))); } if (this.transitionCount != 0) { out.addAll(Collections.nCopies(this.transitionCount, effectColor + this.input)); } } else { for (int i = 0; i <= this.input.length(); i++) { out.addAll(Collections.nCopies(this.effectLength, addAtIndex(primaryColor + this.input, effectColor, i + primaryColor.length()))); } if (this.transitionCount != 0) { out.addAll(Collections.nCopies(this.transitionCount, primaryColor + this.input)); } } return out; } private String addAtIndex(String str, String toAdd, int position) { StringBuilder sb = new StringBuilder(str); sb.insert(position, toAdd); return sb.toString(); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effects/RGBColorChangeAnimation.java ================================================ package dev.simplix.cirrus.common.effects; import com.google.common.base.Preconditions; import dev.simplix.cirrus.common.effect.AbstractMenuAnimation; import dev.simplix.cirrus.common.util.ColorUtils; import net.md_5.bungee.api.ChatColor; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class RGBColorChangeAnimation extends AbstractMenuAnimation { private final List colors; private String colorSuffix; private double step; private RGBColorChangeAnimation( String input, int effectLength, double step, String colorSuffix, List colors ) { super(Preconditions.checkNotNull(input, "input must not be null"), effectLength); this.step = step; this.colors = Preconditions.checkNotNull(colors, "colors must not be null"); this.colorSuffix = Preconditions.checkNotNull(colorSuffix, "colorAddon must not be null"); Preconditions.checkState(colors.size() >= 2, "At least 2 colors must be provided¥"); } public static RGBColorChangeAnimation fat(String input, Color... colors) { return of(input, "§l", 2, 40, colors); } public static RGBColorChangeAnimation of(String input, String colorSuffix, int effectLength, double step, Color... colors) { return new RGBColorChangeAnimation(input, effectLength, step, colorSuffix, Arrays.asList(colors)); } public RGBColorChangeAnimation step(int step) { this.step = step; return this; } public RGBColorChangeAnimation colorSuffix(String colorSuffix) { this.colorSuffix = colorSuffix; return this; } @Override public List calculate() { final List out = new ArrayList<>(); for (int i = 0; i < this.colors.size(); i++) { final Color color = this.colors.get(i); final int index = (this.colors.size() == i + 1) ? 0 : (i + 1); final Color color2 = this.colors.get(index); out.addAll(Collections.nCopies( this.effectLength, ChatColor.of(color) + this.colorSuffix + this.input )); for (Color between : ColorUtils.colorsInBetween(color, color2, this.step)) { out.addAll( Collections.nCopies( this.effectLength, ChatColor.of(between) + this.colorSuffix + this.input ) ); } } return out; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/effects/SimpleChangingItemAnimation.java ================================================ package dev.simplix.cirrus.common.effects; import dev.simplix.cirrus.common.effect.AbstractChangingItemAnimation; import dev.simplix.cirrus.common.item.CirrusItem; import java.util.List; public class SimpleChangingItemAnimation extends AbstractChangingItemAnimation { private final List values; protected SimpleChangingItemAnimation(CirrusItem basis, List values, int effectLength) { super(basis, effectLength); this.values = values; } @Override public List calculate() { return this.values; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/handler/ActionHandler.java ================================================ package dev.simplix.cirrus.common.handler; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.model.Click; /** * {@link ActionHandler}s are functions that get called when a click on an {@link * InventoryMenuItemWrapper} occurs. */ @FunctionalInterface public interface ActionHandler { CallResult handle(Click click); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/handler/AutoCancellingActionHandler.java ================================================ package dev.simplix.cirrus.common.handler; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.model.Click; @FunctionalInterface public interface AutoCancellingActionHandler extends ActionHandler { @Override default CallResult handle(Click click) { onHandle(click); return CallResult.DENY_GRABBING; } void onHandle(Click click); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedItemStackModel.java ================================================ package dev.simplix.cirrus.common.i18n; import dev.simplix.cirrus.common.Utils; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.protocolize.data.ItemType; import lombok.*; import lombok.experimental.Accessors; import net.querz.nbt.tag.CompoundTag; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @Data @Builder @Accessors(fluent = true) @ToString @NoArgsConstructor @AllArgsConstructor public class LocalizedItemStackModel { @Builder.Default private LocalizedString displayName = new LocalizedString(new HashMap<>()); @Builder.Default private LocalizedStringList lore = new LocalizedStringList(new HashMap<>()); @Builder.Default private ItemType itemType = ItemType.STONE; @Builder.Default private byte amount = 1; @Builder.Default private short durability = -1; @Builder.Default private String actionHandler = "noAction"; @Builder.Default private List actionArguments = Collections.emptyList(); @Builder.Default private int[] slots = new int[0]; @Builder.Default @NonNull private CompoundTag nbt = new CompoundTag(); public LocalizedItemStackModel glow() { Utils.glow(this.nbt); return this; } public LocalizedItemStackModel texture(@NonNull String texture) { Utils.texture(this.nbt, texture); return this; } public CirrusItem localize(Locale locale, String... replacements) { return Localizer.localize( this, locale, replacements ); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedString.java ================================================ package dev.simplix.cirrus.common.i18n; import lombok.NonNull; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class LocalizedString { private final Map translations = new HashMap<>(); public LocalizedString(@NonNull Map stringMap) { this.translations.putAll(stringMap); } /** * @return The map with all translations */ public Map translations() { return this.translations; } /** * Returns the localized string for the given {@link Locale}. If the given locale is not * available, it will return the first available translation. If there aren't any translations, it * will return "missigno." * * @param locale The desired locale * @return the localized string or "missigno." */ public String translated(Locale locale) { return this.translations.getOrDefault( locale.getLanguage(), this.translations.getOrDefault( this.translations.keySet().stream().findFirst().orElse(""), "missgno.")); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedStringDeserializer.java ================================================ package dev.simplix.cirrus.common.i18n; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import lombok.NonNull; import java.lang.reflect.Type; import java.util.Map; public class LocalizedStringDeserializer implements JsonDeserializer { @Override public LocalizedString deserialize( @NonNull JsonElement jsonElement, @NonNull Type type, @NonNull JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { Map stringMap = jsonDeserializationContext.deserialize( jsonElement, new TypeToken>() { }.getType()); return new LocalizedString(stringMap); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedStringList.java ================================================ package dev.simplix.cirrus.common.i18n; import lombok.NoArgsConstructor; import lombok.NonNull; import java.util.*; @NoArgsConstructor public class LocalizedStringList { private final Map> translations = new HashMap<>(); public LocalizedStringList(@NonNull Map> stringListMap) { this.translations.putAll(stringListMap); } /** * @return The map with all translations */ public Map> translations() { return this.translations; } private final List forceAdded = new ArrayList<>(); /** * Returns the localized string list for the given {@link Locale}. If the given locale is not * available, it will return the first available translation. If there aren't any translations, it * will return an empty list. * * @param locale The desired locale * @return the localized string list */ public List translated(@NonNull Locale locale) { if (this.translations.isEmpty()) { return Collections.emptyList(); } String fallback = this.translations.keySet().iterator().next(); final List out = new ArrayList<>(this.translations.getOrDefault( locale.getLanguage(), this.translations.getOrDefault( fallback, Collections.emptyList())) ); out.addAll(this.forceAdded); return out; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedStringListDeserializer.java ================================================ package dev.simplix.cirrus.common.i18n; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import lombok.NonNull; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class LocalizedStringListDeserializer implements JsonDeserializer { @Override public LocalizedStringList deserialize( @NonNull JsonElement jsonElement, @NonNull Type type, @NonNull JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { Map> stringListMap = jsonDeserializationContext.deserialize( jsonElement, new TypeToken>>() { }.getType()); return new LocalizedStringList(stringListMap); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedStringListSerializer.java ================================================ package dev.simplix.cirrus.common.i18n; import com.google.gson.JsonElement; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import lombok.NonNull; import java.lang.reflect.Type; public class LocalizedStringListSerializer implements JsonSerializer { @Override public JsonElement serialize( @NonNull LocalizedStringList localizedStringList, @NonNull Type type, @NonNull JsonSerializationContext jsonSerializationContext) { return jsonSerializationContext.serialize(localizedStringList.translations()); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/LocalizedStringSerializer.java ================================================ package dev.simplix.cirrus.common.i18n; import com.google.gson.JsonElement; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import lombok.NonNull; import java.lang.reflect.Type; public class LocalizedStringSerializer implements JsonSerializer { @Override public JsonElement serialize( @NonNull LocalizedString localizedString, @NonNull Type type, @NonNull JsonSerializationContext jsonSerializationContext) { return jsonSerializationContext.serialize(localizedString.translations()); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/Localizer.java ================================================ package dev.simplix.cirrus.common.i18n; import dev.simplix.cirrus.common.item.CirrusItem; import lombok.NonNull; import net.querz.nbt.io.SNBTUtil; import net.querz.nbt.tag.CompoundTag; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; public final class Localizer { public static List localize( LocalizedStringList localizedStringList, @NonNull Locale locale, String... replacements) { if (localizedStringList == null) { return Collections.emptyList(); } return Arrays.asList(Replacer.of(localizedStringList.translated(locale)) .replaceAll((Object[]) replacements).replacedMessage()); } public static String localize( LocalizedString localizedString, @NonNull Locale locale, String... replacements) { if (localizedString == null) { return ""; } return Replacer .of(localizedString.translated(locale)) .replaceAll((Object[]) replacements) .replacedMessageJoined(); } public static CirrusItem localize( @NonNull LocalizedItemStackModel model, @NonNull Locale locale, @NonNull String... replacements) { return CirrusItem.of(localize(model.displayName(), locale, replacements)) .actionArguments(Arrays.asList(Replacer .of(model.actionArguments() == null ? Collections.emptyList() : model.actionArguments()) .replaceAll((Object[]) replacements) .replacedMessage())) .actionHandler(model.actionHandler()) .amount(model.amount()) .durability(model.durability()) .itemType(model.itemType()) .lore(localize(model.lore(), locale, replacements)) .nbt(formatNbt(model.nbt(), replacements)) .slots(model.slots()); } private static CompoundTag formatNbt( @Nullable CompoundTag compoundTag, @NonNull String... replacements) { if (compoundTag == null) { return null; } try { String mojangson = SNBTUtil.toSNBT(compoundTag); return (CompoundTag) SNBTUtil.fromSNBT(Replacer.of(mojangson) .replaceAll((Object[]) replacements).replacedMessageJoined()); } catch (IOException ioException) { // Ignored } return compoundTag; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/i18n/Replacer.java ================================================ package dev.simplix.cirrus.common.i18n; import com.google.common.base.Preconditions; import lombok.Getter; import lombok.NonNull; import lombok.experimental.Accessors; import lombok.val; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * This is a utility class for handy message replacements. Placeholders begin with { and are ending * with } *
* Example: *
{viewer} */ @Getter @Accessors(fluent = true) public final class Replacer { public static final String DELIMITER = "\n"; private final List messages; //Messages to replace private final List variables = new ArrayList<>(); private final List replacements = new ArrayList<>(); private Replacer(List messages) { // Cloning our messages this.messages = new ArrayList<>(messages); } // ---------------------------------------------------------------------------------------------------- // Static Factory methods // ---------------------------------------------------------------------------------------------------- public static Replacer of(@NonNull final String... messages) { return new Replacer(Arrays.asList(messages)); } public static Replacer of(@NonNull final List messages) { return new Replacer(messages); } public static Replacer ofMultilineString(@NonNull final String multilineString) { return new Replacer(Arrays.asList(multilineString.split(DELIMITER))); } public final Replacer find(@NonNull final String... variables) { this.variables.clear(); this.variables.addAll(Arrays.asList(variables)); return this; } public final Replacer replace(@NonNull final Object... replacements) { this.replacements.clear(); this.replacements.addAll(Arrays.asList(replacements)); return this; } public Replacer set(final int index, @NonNull final String message) { this.messages.set(index, message); return this; } /** * Replaces all variables with replacements. * * @param associativeArray Variable, Replacement, Variable, Replacement */ public final Replacer replaceAll(@NonNull final Object... associativeArray) { this.variables.clear(); this.replacements.clear(); //Even: Value for (int i = 0; i < associativeArray.length; i++) { if (i % 2 == 0) { //Odd: Key val raw = associativeArray[i]; Preconditions.checkState( raw instanceof String, "Expected String at " + raw + ", got " + raw.getClass() .getSimpleName()); this.variables.add((String) raw); } else { this.replacements.add(associativeArray[i]); } } return this; } /** * Method to replace the registered Replacers. */ public String[] replacedMessage() { Preconditions.checkState( this.replacements.size() == this.variables.size(), "Variables " + this.variables.size() + " != replacements " + this.replacements.size(), "Variables: " + this.variables.toString(), "Replacments: " + this.replacements ); // Join and replace as 1 message for maximum performance String message = String.join(DELIMITER, this.messages); for (int i = 0; i < this.variables.size(); i++) { String found = this.variables.get(i); { // Auto insert brackets if (!found.startsWith("{")) { found = "{" + found; } if (!found.endsWith("}")) { found = found + "}"; } } final Object rep = i <= this.replacements.size() ? this.replacements.get(i) : null; message = message.replace(found, rep == null ? "" : rep.toString()); } return message.split(DELIMITER); } /** * Same as {@link #replacedMessage()} but joined using {@link String#join(CharSequence, * CharSequence...)} and the {@link #DELIMITER} */ public String replacedMessageJoined() { return String.join(DELIMITER, replacedMessage()); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/item/CirrusItem.java ================================================ package dev.simplix.cirrus.common.item; import dev.simplix.cirrus.common.Utils; import dev.simplix.cirrus.common.effect.AbstractMenuAnimation; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import lombok.experimental.Accessors; import net.querz.nbt.tag.CompoundTag; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Supplier; @Accessors(fluent = true) public class CirrusItem { @NonNull private String displayName = "Example-DisplayName"; @Nullable private AbstractMenuAnimation titleEffect = null; private List lore = Collections.emptyList(); @Nullable private Supplier> loreSupplier = null; private ItemType itemType = ItemType.STONE; private byte amount = 1; private short durability = -1; private String actionHandler = "noAction"; private List actionArguments = Collections.emptyList(); private int[] slots = new int[0]; @NonNull private CompoundTag nbt; private CirrusItem(@NonNull String displayName, @Nullable AbstractMenuAnimation titleEffect, List lore, @Nullable Supplier> loreSupplier, ItemType itemType, byte amount, short durability, String actionHandler, List actionArguments, int[] slots, @NonNull CompoundTag nbt) { this.displayName = displayName; this.titleEffect = titleEffect; this.lore = lore; this.loreSupplier = loreSupplier; this.itemType = itemType; this.amount = amount; this.durability = durability; this.actionHandler = actionHandler; this.actionArguments = actionArguments; this.slots = slots; this.nbt = nbt; } private CirrusItem() { } // ---------------------------------------------------------------------------------------------------- // Instancing // ---------------------------------------------------------------------------------------------------- public static CirrusItem of(String name, ItemType type) { return new CirrusItem().displayName(name).itemType(type); } public static CirrusItem of(String name) { return of(name, ItemType.STONE); } public static CirrusItem animated(AbstractMenuAnimation effect, ItemType type) { return new CirrusItem().itemType(type).titleEffect(effect); } public static CirrusItem animated(AbstractMenuAnimation effect) { return animated(effect, ItemType.STONE); } // ---------------------------------------------------------------------------------------------------- // Chained setters // ---------------------------------------------------------------------------------------------------- public CirrusItem lore(String... lines) { this.lore = Arrays.asList(lines); return this; } public CirrusItem slot(int... slots) { this.slots = slots; return this; } public String displayNam() { if (this.titleEffect != null) { return this.titleEffect.next(); } return this.displayName; } public CirrusItem glow() { Utils.glow(this.nbt); return this; } public CirrusItem texture(@NonNull String texture) { Utils.texture(this.nbt, texture); return this; } public CirrusItem copy() { return new CirrusItem( this.displayName, this.titleEffect, this.lore, this.loreSupplier, this.itemType, this.amount, this.durability, this.actionHandler, this.actionArguments, this.slots, this.nbt ); } public @NonNull String displayName() { return this.displayName; } public @Nullable AbstractMenuAnimation titleEffect() { return this.titleEffect; } public List lore() { if (this.loreSupplier != null) { return this.loreSupplier.get(); } return this.lore; } public @Nullable Supplier> loreSupplier() { return this.loreSupplier; } public ItemType itemType() { return this.itemType; } public byte amount() { return this.amount; } public short durability() { return this.durability; } public String actionHandler() { return this.actionHandler; } public List actionArguments() { return this.actionArguments; } public int[] slots() { return this.slots; } public @NonNull CompoundTag nbt() { return this.nbt; } public CirrusItem displayName(@NonNull String displayName) { this.displayName = displayName; return this; } public CirrusItem titleEffect(@Nullable AbstractMenuAnimation titleEffect) { this.titleEffect = titleEffect; return this; } public CirrusItem lore(List lore) { this.lore = lore; return this; } public CirrusItem loreSupplier(@Nullable Supplier> loreSupplier) { this.loreSupplier = loreSupplier; return this; } public CirrusItem itemType(ItemType itemType) { this.itemType = itemType; return this; } public CirrusItem amount(byte amount) { this.amount = amount; return this; } public CirrusItem durability(short durability) { this.durability = durability; return this; } public CirrusItem actionHandler(String actionHandler) { this.actionHandler = actionHandler; return this; } public CirrusItem actionArguments(List actionArguments) { this.actionArguments = actionArguments; return this; } public CirrusItem slots(int[] slots) { this.slots = slots; return this; } public CirrusItem nbt(@NonNull CompoundTag nbt) { this.nbt = nbt; return this; } @Override public boolean equals(final Object o) { if (o == this) { return true; } if (!(o instanceof CirrusItem)) { return false; } final CirrusItem other = (CirrusItem) o; if (!other.canEqual((Object) this)) { return false; } final Object this$displayName = this.displayName(); final Object other$displayName = other.displayName(); if (this$displayName == null ? other$displayName != null : !this$displayName.equals(other$displayName)) { return false; } final Object this$titleEffect = this.titleEffect(); final Object other$titleEffect = other.titleEffect(); if (this$titleEffect == null ? other$titleEffect != null : !this$titleEffect.equals(other$titleEffect)) { return false; } final Object this$lore = this.lore(); final Object other$lore = other.lore(); if (this$lore == null ? other$lore != null : !this$lore.equals(other$lore)) { return false; } final Object this$loreSupplier = this.loreSupplier(); final Object other$loreSupplier = other.loreSupplier(); if (this$loreSupplier == null ? other$loreSupplier != null : !this$loreSupplier.equals(other$loreSupplier)) { return false; } final Object this$itemType = this.itemType(); final Object other$itemType = other.itemType(); if (this$itemType == null ? other$itemType != null : !this$itemType.equals(other$itemType)) { return false; } if (this.amount() != other.amount()) { return false; } if (this.durability() != other.durability()) { return false; } final Object this$actionHandler = this.actionHandler(); final Object other$actionHandler = other.actionHandler(); if (this$actionHandler == null ? other$actionHandler != null : !this$actionHandler.equals(other$actionHandler)) { return false; } final Object this$actionArguments = this.actionArguments(); final Object other$actionArguments = other.actionArguments(); if (this$actionArguments == null ? other$actionArguments != null : !this$actionArguments.equals(other$actionArguments)) { return false; } if (!Arrays.equals(this.slots(), other.slots())) { return false; } final Object this$nbt = this.nbt(); final Object other$nbt = other.nbt(); if (this$nbt == null ? other$nbt != null : !this$nbt.equals(other$nbt)) { return false; } return true; } protected boolean canEqual(final Object other) { return other instanceof CirrusItem; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $displayName = this.displayName(); result = result * PRIME + ($displayName == null ? 43 : $displayName.hashCode()); final Object $titleEffect = this.titleEffect(); result = result * PRIME + ($titleEffect == null ? 43 : $titleEffect.hashCode()); final Object $lore = this.lore(); result = result * PRIME + ($lore == null ? 43 : $lore.hashCode()); final Object $loreSupplier = this.loreSupplier(); result = result * PRIME + ($loreSupplier == null ? 43 : $loreSupplier.hashCode()); final Object $itemType = this.itemType(); result = result * PRIME + ($itemType == null ? 43 : $itemType.hashCode()); result = result * PRIME + this.amount(); result = result * PRIME + this.durability(); final Object $actionHandler = this.actionHandler(); result = result * PRIME + ($actionHandler == null ? 43 : $actionHandler.hashCode()); final Object $actionArguments = this.actionArguments(); result = result * PRIME + ($actionArguments == null ? 43 : $actionArguments.hashCode()); result = result * PRIME + Arrays.hashCode(this.slots()); final Object $nbt = this.nbt(); result = result * PRIME + ($nbt == null ? 43 : $nbt.hashCode()); return result; } @Override public String toString() { return "CirrusItem(displayName=" + this.displayName() + ", titleEffect=" + this.titleEffect() + ", lore=" + this.lore() + ", loreSupplier=" + this.loreSupplier() + ", itemType=" + this.itemType() + ", amount=" + this.amount() + ", durability=" + this.durability() + ", actionHandler=" + this.actionHandler() + ", actionArguments=" + this.actionArguments() + ", slots=" + Arrays.toString(this.slots()) + ", nbt=" + this.nbt() + ")"; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/item/Items.java ================================================ package dev.simplix.cirrus.common.item; import dev.simplix.cirrus.common.effects.RGBColorChangeAnimation; import lombok.experimental.UtilityClass; import java.awt.*; @UtilityClass public class Items { public CirrusItem rgb(String displayName, Color... colors) { return CirrusItem .animated(RGBColorChangeAnimation.fat(displayName, colors)); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/item/ProtocolizeMenuItemWrapper.java ================================================ package dev.simplix.cirrus.common.item; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.protocolize.api.chat.ChatElement; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import net.md_5.bungee.api.chat.BaseComponent; import net.querz.nbt.tag.CompoundTag; import java.util.List; import java.util.stream.Collectors; public class ProtocolizeMenuItemWrapper implements MenuItemWrapper { private final ItemStack itemStack; public ProtocolizeMenuItemWrapper(ItemStack itemStack) { this.itemStack = itemStack; } @Override public String displayName() { return this.itemStack.displayName().asLegacyText(); } @Override public BaseComponent[] displayNameComponents() { return (BaseComponent[]) this.itemStack.displayName().asComponent(); } @Override public List lore() { return this.itemStack.lore().stream().map(ChatElement::asLegacyText).collect(Collectors.toList()); } @Override public List loreComponents() { return (List) this.itemStack.lore().stream().map(ChatElement::asComponent).collect(Collectors.toList()); } @Override public ItemType type() { return this.itemStack.itemType(); } @Override public CompoundTag nbt() { return this.itemStack.nbtData(); } @Override public int amount() { return this.itemStack.amount(); } @Override public short durability() { return this.itemStack.durability(); } @Override public void type(@NonNull ItemType type) { this.itemStack.itemType(type); } @Override public void displayName(@NonNull String displayName) { this.itemStack.displayName(ChatElement.ofLegacyText(displayName)); } @Override public void displayNameComponents(BaseComponent... baseComponents) { this.itemStack.displayName(ChatElement.of(baseComponents)); } @Override public void lore(@NonNull List lore) { this.itemStack.lore(lore.stream().map(ChatElement::ofLegacyText).collect(Collectors.toList())); } @Override public void loreComponents(@NonNull List lore) { this.itemStack.lore(lore.stream().map(ChatElement::of).collect(Collectors.toList())); } @Override public void nbt(@NonNull CompoundTag compoundTag) { this.itemStack.nbtData(compoundTag); } @Override public void amount(int amount) { this.itemStack.amount((byte) amount); } @Override public void durability(short durability) { this.itemStack.durability(durability); } @Override public T handle() { return (T) this.itemStack; } @Override public String toString() { return handle().toString(); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menu/AbstractConfigurableMenu.java ================================================ package dev.simplix.cirrus.common.menu; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; import lombok.Getter; import lombok.NonNull; import lombok.experimental.Accessors; import java.util.HashMap; import java.util.Locale; import java.util.Map; @Getter @Accessors(fluent = true) public abstract class AbstractConfigurableMenu extends AbstractMenu { private final T configuration; public AbstractConfigurableMenu( @NonNull PlayerWrapper player, @NonNull T configuration, @NonNull Locale locale) { this(player, configuration, locale, new HashMap<>()); } public AbstractConfigurableMenu( @NonNull PlayerWrapper player, @NonNull T configuration, @NonNull Locale locale, @NonNull Map actionHandlerMap) { super(player, configuration.type(), locale, actionHandlerMap); title(configuration.title().translated(locale)); this.configuration = configuration; applyItems(); } @Override protected void updateReplacements() { super.updateReplacements(); topContainer().itemMap().clear(); bottomContainer().itemMap().clear(); topContainer().reservedSlots().clear(); bottomContainer().reservedSlots().clear(); applyItems(); } private void applyItems() { for (int slot : this.configuration.reservedSlots()) { if (slot > topContainer().capacity() - 1) { bottomContainer().reservedSlots().add(slot); } else { topContainer().reservedSlots().add(slot); } } // Set placeholders set(this.configuration.placeholderItem()); // Set other items for (LocalizedItemStackModel model : this.configuration.items()) { set(model); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menu/AbstractMenu.java ================================================ package dev.simplix.cirrus.common.menu; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.container.impl.ItemContainer; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.handler.AutoCancellingActionHandler; import dev.simplix.cirrus.common.i18n.LocalizedItemStackModel; import dev.simplix.cirrus.common.i18n.Localizer; import dev.simplix.cirrus.common.i18n.Replacer; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.protocolize.data.inventory.InventoryType; import lombok.Getter; import lombok.NonNull; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @Getter @Accessors(fluent = true) @Slf4j public abstract class AbstractMenu implements Menu { private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); private final Map actionHandlerMap; private final MenuBuilder menuBuilder = Cirrus.getService(MenuBuilder.class); private final Container topContainer; private final Container bottomContainer; private final InventoryType inventoryType; private final Locale locale; private final PlayerWrapper player; private final int internalId = ID_GENERATOR.incrementAndGet(); private Supplier replacements; private ActionHandler customActionHandler; private Object nativeInventory; private String title; public AbstractMenu( @NonNull PlayerWrapper player, @NonNull InventoryType inventoryType, @NonNull Locale locale) { this(player, inventoryType, locale, new HashMap<>()); } public AbstractMenu( @NonNull PlayerWrapper player, @NonNull InventoryType inventoryType, @NonNull Locale locale, @NonNull Map actionHandlerMap) { this.inventoryType = inventoryType; this.locale = locale; this.player = player; this.replacements = () -> new String[]{"viewer", player.name()}; this.topContainer = new ItemContainer(0, inventoryType.getTypicalSize(player.protocolVersion())); this.bottomContainer = new ItemContainer( inventoryType.getTypicalSize(player.protocolVersion()), 4 * 9); this.actionHandlerMap = actionHandlerMap; } @Override public void registerActionHandler(@NonNull String name, @NonNull AutoCancellingActionHandler actionHandler) { this.actionHandlerMap.put(name, actionHandler); } @Override public void registerActionHandler(@NonNull String name, @NonNull ActionHandler actionHandler) { this.actionHandlerMap.put(name, actionHandler); } @Override @Nullable public ActionHandler actionHandler(@NonNull String name) { return this.actionHandlerMap.get(name); } @Override public void customActionHandler(@NonNull ActionHandler actionHandler) { this.customActionHandler = actionHandler; } @Override public void title(@NonNull String title) { this.title = title; } @Override public String title() { return Replacer.of(this.title).replaceAll((Object[]) replacements().get()).replacedMessageJoined(); } @Override public void replacements(@NonNull Supplier replacements) { this.replacements = replacements; updateReplacements(); } protected void updateReplacements() { } protected void nativeInventory(@NonNull Object nativeInventory) { this.nativeInventory = nativeInventory; } @Override public void build() { if (menuBuilder() == null) { return; } nativeInventory(menuBuilder().build(nativeInventory(), this)); } @Override public void open() { build(); menuBuilder().open(this.player, nativeInventory()); } protected int add(@NonNull LocalizedItemStackModel localizedItemStackModel) { return add(localizedItemStackModel.localize(locale(), this.replacements.get())); } protected int add(@NonNull CirrusItem menuItem) { int slot = topContainer().nextFreeSlot(); this.topContainer.set(slot, menuItem); return slot; } protected int add(@NonNull InventoryMenuItemWrapper inventoryMenuItemWrapper) { int slot = topContainer().nextFreeSlot(); this.topContainer.set(slot, inventoryMenuItemWrapper); return slot; } protected void set(@NonNull LocalizedItemStackModel model) { set(Localizer.localize( model, locale(), replacements().get())); } protected void set(@NonNull CirrusItem model) { for (int slot : model.slots()) { if (slot > topContainer().capacity() - 1) { bottomContainer().set(slot - bottomContainer().baseSlot(), model); } else { topContainer().set(slot, model); } } } @Override public boolean equals(Object o) { if (o == null) { return false; } if (o instanceof AbstractMenu) { final AbstractMenu abstractMenu = (AbstractMenu) o; return abstractMenu.internalId == this.internalId(); } if (this == o) { return true; } return o.equals(nativeInventory()); } @Override public int hashCode() { return Objects.hash( this.actionHandlerMap, this.topContainer, this.bottomContainer, this.inventoryType, this.locale, this.player, this.internalId, this.replacements, this.customActionHandler, this.nativeInventory, this.title); } @Override public void handleException( @Nullable ActionHandler actionHandler, Throwable throwable) { if (actionHandler == null) { this.player.sendMessage( "§cThere was a problem while running your menu. Please take a look at the console."); log.error( "[Cirrus] Exception occurred while running menu " + getClass().getName(), throwable); } else { this.player.sendMessage( "§cThere was a problem while running your action handler. Please take a look at the console."); log.error("[Cirrus] Exception occurred while running action handler for menu " + getClass().getName(), throwable); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menu/ErrorProne.java ================================================ package dev.simplix.cirrus.common.menu; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.util.SafeRunnable; import lombok.NonNull; import org.jetbrains.annotations.Nullable; public interface ErrorProne { default void handleException(@Nullable ActionHandler actionHandler, Throwable throwable) { } /** * Executes error prone code that may throw a exception. When an exception is thrown, it will be * delegated to the exception handler. * * @param runnable The runnable to run */ default void errorProne(@NonNull SafeRunnable runnable) { try { runnable.run(); } catch (Throwable throwable) { handleException(null, throwable); } } /** * Executes error prone code that may throw a exception. When an exception is thrown, it will be * delegated to the exception handler. * * @param runnable The runnable to run * @param finallyRunnable Code that may run finally */ default void errorProne(@NonNull SafeRunnable runnable, @NonNull Runnable finallyRunnable) { try { runnable.run(); } catch (Throwable throwable) { handleException(null, throwable); } finally { finallyRunnable.run(); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menu/Menu.java ================================================ package dev.simplix.cirrus.common.menu; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.handler.AutoCancellingActionHandler; import dev.simplix.protocolize.data.inventory.InventoryType; import lombok.NonNull; import org.jetbrains.annotations.Nullable; import java.util.Locale; import java.util.function.Supplier; public interface Menu extends ErrorProne { /** * @return The inventory type */ InventoryType inventoryType(); void registerActionHandler(@NonNull String name, @NonNull AutoCancellingActionHandler actionHandler); /** * Registers a new action handler * * @param name the name * @param actionHandler the action handler */ void registerActionHandler(@NonNull String name, @NonNull ActionHandler actionHandler); /** * ActionHandler which handles clicks in empty space * * @param actionHandler the action handler */ void customActionHandler(@NonNull ActionHandler actionHandler); /** * This opens the menu for the specified player */ void open(); /** * This builds the menu */ void build(); /** * ActionHandler which handles clicks in empty space * * @return The custom action handler */ ActionHandler customActionHandler(); /** * Returns an action handler by its name * * @param name the name of the desired action handler * @return the action handler or null if not found */ @Nullable ActionHandler actionHandler(@NonNull String name); /** * Returns the {@link Container} for the upper inventory. * * @return container */ Container topContainer(); /** * Returns the {@link Container} for the lower inventory. * * @return container */ Container bottomContainer(); /** * Returns the title of the menu * * @return title string */ String title(); /** * Sets the title of the menu * * @param title title */ void title(@NonNull String title); /** * @return The locale the menu is in */ Locale locale(); /** * Returns the owner of this menu. The current viewer. * * @return The player */ PlayerWrapper player(); /** * Returns a {@link Supplier} which returns a string array used for placeholder replacement. * * @return Supplier for string array */ Supplier replacements(); /** * Sets a {@link Supplier} which returns a string array used for placeholder replacement. * * @param supplier supplier */ void replacements(Supplier supplier); /** * Called when leaving the current menu. * * @param inventorySwitch true if a new menu was built within the last 55ms */ default void handleClose(boolean inventorySwitch) { } /** * Converts an object into an ItemStackWrapper. * * @param object the object to convert * @return the wrapper object */ default MenuItemWrapper wrapItemStack(@NonNull Object object) { return Converters.convert(object, MenuItemWrapper.class); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menu/MenuBuilder.java ================================================ package dev.simplix.cirrus.common.menu; import dev.simplix.cirrus.common.business.PlayerWrapper; import lombok.NonNull; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.Optional; import java.util.UUID; public interface MenuBuilder { T build(@Nullable T prebuild, @NonNull Menu menu); void open(@NonNull PlayerWrapper playerWrapper, @NonNull T inventoryImpl); @Nullable Menu menuByHandle(@Nullable Object handle); default Optional findMenuByHandle(@Nullable Object handle) { return Optional.ofNullable(menuByHandle(handle)); } void destroyMenusOfPlayer(@NonNull UUID uniqueId); Map.Entry lastBuildOfPlayer(@NonNull UUID uniqueId); void invalidate(@NonNull Menu menu); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menus/AbstractBrowserMenu.java ================================================ package dev.simplix.cirrus.common.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.model.Click; import lombok.NonNull; import java.util.*; import java.util.Map.Entry; public abstract class AbstractBrowserMenu extends MultiPageMenu { protected Map slotValueMap = new HashMap<>(); protected Map out = new HashMap<>(); public AbstractBrowserMenu( @NonNull PlayerWrapper player, @NonNull MultiPageMenuConfiguration configuration, @NonNull Locale locale) { this(player, configuration, locale, new HashMap<>()); } public AbstractBrowserMenu( @NonNull PlayerWrapper player, @NonNull MultiPageMenuConfiguration configuration, @NonNull Locale locale, @NonNull Map actionHandlerMap) { super(player, configuration, locale, actionHandlerMap); registerActionHandler("click", click -> { final T value = this.slotValueMap.get(click.slot()); if (value == null) { return; } click(click, value); }); } protected abstract void click(Click click, T value); protected abstract List values(); protected abstract CirrusItem map(T value); protected Map mappedValues() { if (this.out != null && !this.out.isEmpty()) { return this.out; } this.out = new HashMap<>(); for (T value : values()) { this.out.put(value, map(value)); } return this.out; } protected void insert() { for (Entry entry : mappedValues().entrySet()) { final CirrusItem value = entry.getValue(); final Integer slot = add(value, "click", new ArrayList<>()); this.slotValueMap.put(slot, entry.getKey()); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menus/MultiPageMenu.java ================================================ package dev.simplix.cirrus.common.menus; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.menu.AbstractConfigurableMenu; import dev.simplix.cirrus.common.menu.AbstractMenu; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.common.model.CallResult; import lombok.Getter; import lombok.NonNull; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import java.util.*; import java.util.function.Supplier; @Slf4j @Accessors(fluent = true) public class MultiPageMenu extends AbstractMenu { private final MenuBuilder menuBuilder = Cirrus.getService(MenuBuilder.class); @Getter private final List pages = new LinkedList<>(); @Getter private final MultiPageMenuConfiguration configuration; private int currentPage = 1; public MultiPageMenu( @NonNull PlayerWrapper player, @NonNull MultiPageMenuConfiguration configuration, @NonNull Locale locale) { this(player, configuration, locale, new HashMap<>()); } public MultiPageMenu( @NonNull PlayerWrapper player, @NonNull MultiPageMenuConfiguration configuration, @NonNull Locale locale, @NonNull Map actionHandlerMap) { super(player, configuration.type(), locale, actionHandlerMap); this.configuration = configuration; title(configuration.title().translated(locale)); this.pages.add(new PageMenu(player, configuration, locale)); registerActionHandlers(); configuration.nextPageItem().actionHandler("nextPage"); configuration.previousPageItem().actionHandler("previousPage"); Arrays .stream(configuration.nextPageItem().slots()) .forEach(value -> topContainer().reservedSlots().add(value)); Arrays .stream(configuration.previousPageItem().slots()) .forEach(value -> topContainer().reservedSlots().add(value)); replacements(() -> new String[]{ "viewer", player.name(), "page", Integer.toString(this.currentPage), "pageCount", Integer.toString(this.pages.size())}); } private void registerActionHandlers() { registerActionHandler("nextPage", click -> { if (this.currentPage == this.pages.size()) { return CallResult.DENY_GRABBING; } this.currentPage++; build(); return CallResult.DENY_GRABBING; }); registerActionHandler("previousPage", click -> { if (this.currentPage == 1) { return CallResult.DENY_GRABBING; } this.currentPage--; build(); return CallResult.DENY_GRABBING; }); } @Override public void build() { currentPage().build(); } @Override public void open() { currentPage(1); currentPage().open(); } @Override public MenuBuilder menuBuilder() { return this.menuBuilder; } @Override public Container bottomContainer() { return currentPage().bottomContainer(); } @Override public Container topContainer() { return currentPage().topContainer(); } public Menu currentPage() { return this.pages.get(this.currentPage - 1); } public List pages() { return this.pages; } public int currentPageNumber() { return this.currentPage; } public void currentPage(int page) { this.currentPage = page; } public void newPage() { this.pages.add(new PageMenu(player(), configuration(), locale())); this.currentPage++; } public int add(@NonNull CirrusItem model, String actionHandler, List arguments) { return add(wrapItemStack(model), actionHandler, arguments); } @Override public int add(@NonNull InventoryMenuItemWrapper inventoryItemWrapper) { int slot = currentPage().topContainer().nextFreeSlot(); int oldPage = this.currentPage; if (slot == -1) { if (this.pages.size() > this.currentPage) { this.currentPage = this.pages.size(); int out = this.add(inventoryItemWrapper); currentPage(oldPage); return out; } newPage(); if (currentPage().topContainer().nextFreeSlot() == -1) { log.info("[Cirrus] Cannot add item to " + MultiPageMenu.this.getClass().getSimpleName() + ": No space in new page!"); currentPage(oldPage); return -1; } this.add(inventoryItemWrapper); } else { currentPage().topContainer().set(slot, inventoryItemWrapper); } currentPage(oldPage); return slot; } public int add( @NonNull MenuItemWrapper menuItemWrapper, @NonNull String actionHandler, @NonNull List actionArgs) { int slot = currentPage().topContainer().nextFreeSlot(); int oldPage = this.currentPage; if (slot == -1) { if (this.pages.size() > this.currentPage) { this.currentPage = this.pages.size(); int out = this.add(menuItemWrapper, actionHandler, actionArgs); currentPage(oldPage); return out; } newPage(); if (currentPage().topContainer().nextFreeSlot() == -1) { log.info("[Cirrus] Cannot add item to " + MultiPageMenu.this.getClass().getSimpleName() + ": No space in new page!"); currentPage(oldPage); return -1; } this.add(menuItemWrapper, actionHandler, actionArgs); } else { currentPage().topContainer().add(menuItemWrapper, actionHandler, actionArgs); } currentPage(oldPage); return slot; } class PageMenu extends AbstractConfigurableMenu { public PageMenu( @NonNull PlayerWrapper player, @NonNull MenuConfiguration configuration, @NonNull Locale locale) { super(player, configuration, locale); } @Override public Supplier replacements() { return MultiPageMenu.this.replacements(); } @Override public String title() { return MultiPageMenu.this.title(); } @Override public ActionHandler actionHandler(@NonNull String name) { return MultiPageMenu.this.actionHandler(name); } @Override protected void nativeInventory(@NonNull Object nativeInventory) { MultiPageMenu.this.nativeInventory(nativeInventory); } @Override public MenuBuilder menuBuilder() { return MultiPageMenu.this.menuBuilder(); } @Override public void build() { if (MultiPageMenu.this.currentPage > 1) { set(MultiPageMenu.this.configuration().previousPageItem()); } if (MultiPageMenu.this.pages.size() > MultiPageMenu.this.currentPage) { set(MultiPageMenu.this.configuration().nextPageItem()); } if (menuBuilder() == null) { return; } nativeInventory(menuBuilder().build(nativeInventory(), MultiPageMenu.this)); } @Override public Object nativeInventory() { return MultiPageMenu.this.nativeInventory(); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/menus/SimpleMenu.java ================================================ package dev.simplix.cirrus.common.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.menu.AbstractConfigurableMenu; import lombok.NonNull; import java.util.Locale; import java.util.Map; public class SimpleMenu extends AbstractConfigurableMenu { public SimpleMenu(@NonNull PlayerWrapper player, @NonNull MenuConfiguration configuration, @NonNull Locale locale) { super(player, configuration, locale); } public SimpleMenu(@NonNull PlayerWrapper player, @NonNull MenuConfiguration configuration, @NonNull Locale locale, @NonNull Map actionHandlerMap) { super(player, configuration, locale, actionHandlerMap); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/model/CallResult.java ================================================ package dev.simplix.cirrus.common.model; public enum CallResult { DENY_GRABBING, ALLOW_GRABBING } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/model/Click.java ================================================ package dev.simplix.cirrus.common.model; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.protocolize.api.ClickType; import lombok.NonNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; /** * A click contains information about a click performed on an {@link InventoryMenuItemWrapper}. */ public final class Click { private final ClickType clickType; private final Menu clickedMenu; private final InventoryMenuItemWrapper clickedItem; private final int slot; public Click( @NonNull ClickType clickType, @NonNull Menu clickedMenu, @Nullable InventoryMenuItemWrapper clickedItem, int slot) { this.clickType = clickType; this.clickedMenu = clickedMenu; this.clickedItem = clickedItem; this.slot = slot; } public PlayerWrapper player() { return this.clickedMenu.player(); } public ClickType clickType() { return this.clickType; } public Menu clickedMenu() { return this.clickedMenu; } public List arguments() { if (this.clickedItem != null) { return this.clickedItem.actionArguments(); } return new ArrayList<>(); } public T clickedItem() { return (T) this.clickedItem; } public int slot() { return this.slot; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/mojangson/MojangsonScope.java ================================================ /* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dev.simplix.cirrus.common.mojangson; /** * Lexical scoping elements within a JSON reader or writer. * * @author Jesse Wilson * @since 1.6 */ final class MojangsonScope { /** * An array with no elements requires no separators or newlines before it is closed. */ static final int EMPTY_ARRAY = 1; /** * A array with at least one value requires a comma and newline before the next element. */ static final int NONEMPTY_ARRAY = 2; /** * An object with no name/value pairs requires no separators or newlines before it is closed. */ static final int EMPTY_OBJECT = 3; /** * An object whose most recent element is a key. The next element must be a value. */ static final int DANGLING_NAME = 4; /** * An object with at least one name/value pair requires a comma and newline before the next * element. */ static final int NONEMPTY_OBJECT = 5; /** * No object or array has been started. */ static final int EMPTY_DOCUMENT = 6; /** * A document with at an array or object. */ static final int NONEMPTY_DOCUMENT = 7; /** * A document that's been closed and cannot be accessed. */ static final int CLOSED = 8; } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/mojangson/MojangsonWriter.java ================================================ package dev.simplix.cirrus.common.mojangson; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.io.Writer; import java.util.Arrays; /** * A modified version of {@link JsonWriter} only using quotes when it is necessary. MojangsonWriter * is lenient by default. */ public class MojangsonWriter extends JsonWriter { /* * From RFC 7159, "All Unicode characters may be placed within the * quotation marks except for the characters that must be escaped: * quotation mark, reverse solidus, and the control characters * (U+0000 through U+001F)." * * We also escape '\u2028' and '\u2029', which JavaScript interprets as * newline characters. This prevents eval() from failing with a syntax * error. http://code.google.com/p/google-gson/issues/detail?id=341 */ private static final String[] REPLACEMENT_CHARS; private static final String[] HTML_SAFE_REPLACEMENT_CHARS; static { REPLACEMENT_CHARS = new String[128]; for (int i = 0; i <= 0x1f; i++) { REPLACEMENT_CHARS[i] = String.format("\\u%04x", (int) i); } REPLACEMENT_CHARS['"'] = "\\\""; REPLACEMENT_CHARS['\\'] = "\\\\"; REPLACEMENT_CHARS['\t'] = "\\t"; REPLACEMENT_CHARS['\b'] = "\\b"; REPLACEMENT_CHARS['\n'] = "\\n"; REPLACEMENT_CHARS['\r'] = "\\r"; REPLACEMENT_CHARS['\f'] = "\\f"; HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone(); HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c"; HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e"; HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026"; HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d"; HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027"; } /** * The output data, containing at most one top-level array or object. */ private final Writer out; private int[] stack = new int[32]; private int stackSize = 0; /** * A string containing a full set of spaces for a single level of indentation, or null for no * pretty printing. */ private String indent; /** * The name/value separator; either ":" or ": ". */ private String separator = ":"; private boolean lenient; private boolean htmlSafe; private String deferredName; private boolean serializeNulls = true; { push(MojangsonScope.EMPTY_DOCUMENT); } /** * Creates a new instance that writes a MOJANGSON-encoded stream to {@code out}. For best * performance, ensure {@link Writer} is buffered; wrapping in {@link java.io.BufferedWriter * BufferedWriter} if necessary. */ public MojangsonWriter(Writer out) { super(out); if (out == null) { throw new NullPointerException("out == null"); } this.out = out; setLenient(true); } /** * Begins encoding a new array. Each call to this method must be paired with a call to {@link * #endArray}. * * @return this writer. */ public MojangsonWriter beginArray() throws IOException { writeDeferredName(); return open(MojangsonScope.EMPTY_ARRAY, '['); } /** * Ends encoding the current array. * * @return this writer. */ public MojangsonWriter endArray() throws IOException { return close(MojangsonScope.EMPTY_ARRAY, MojangsonScope.NONEMPTY_ARRAY, ']'); } /** * Begins encoding a new object. Each call to this method must be paired with a call to {@link * #endObject}. * * @return this writer. */ public MojangsonWriter beginObject() throws IOException { writeDeferredName(); return open(MojangsonScope.EMPTY_OBJECT, '{'); } /** * Ends encoding the current object. * * @return this writer. */ public MojangsonWriter endObject() throws IOException { return close(MojangsonScope.EMPTY_OBJECT, MojangsonScope.NONEMPTY_OBJECT, '}'); } /** * Enters a new scope by appending any necessary whitespace and the given bracket. */ private MojangsonWriter open(int empty, char openBracket) throws IOException { beforeValue(); push(empty); out.write(openBracket); return this; } /** * Closes the current scope by appending any necessary whitespace and the given bracket. */ private MojangsonWriter close(int empty, int nonempty, char closeBracket) throws IOException { int context = peek(); if (context != nonempty && context != empty) { throw new IllegalStateException("Nesting problem."); } if (deferredName != null) { throw new IllegalStateException("Dangling name: " + deferredName); } stackSize--; if (context == nonempty) { newline(); } out.write(closeBracket); return this; } private void push(int newTop) { if (stackSize == stack.length) { stack = Arrays.copyOf(stack, stackSize * 2); } stack[stackSize++] = newTop; } /** * Returns the value on the top of the stack. */ private int peek() { if (stackSize == 0) { throw new IllegalStateException("MojangsonWriter is closed."); } return stack[stackSize - 1]; } /** * Replace the value on the top of the stack with the given value. */ private void replaceTop(int topOfStack) { stack[stackSize - 1] = topOfStack; } /** * Encodes the property name. * * @param name the name of the forthcoming value. May not be null. * @return this writer. */ public MojangsonWriter name(String name) throws IOException { if (name == null) { throw new NullPointerException("name == null"); } if (deferredName != null) { throw new IllegalStateException(); } if (stackSize == 0) { throw new IllegalStateException("MojangsonWriter is closed."); } deferredName = name; return this; } private void writeDeferredName() throws IOException { if (deferredName != null) { beforeName(); string(deferredName); deferredName = null; } } /** * Encodes {@code value}. * * @param value the literal string value, or null to encode a null literal. * @return this writer. */ public MojangsonWriter value(String value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); beforeValue(); string(value); return this; } /** * Writes {@code value} directly to the writer without quoting or escaping. * * @param value the literal string value, or null to encode a null literal. * @return this writer. */ public MojangsonWriter jsonValue(String value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); beforeValue(); out.append(value); return this; } /** * Encodes {@code null}. * * @return this writer. */ public MojangsonWriter nullValue() throws IOException { if (deferredName != null) { if (serializeNulls) { writeDeferredName(); } else { deferredName = null; return this; // skip the name and the value } } beforeValue(); out.write("null"); return this; } /** * Encodes {@code value}. * * @return this writer. */ public MojangsonWriter value(boolean value) throws IOException { writeDeferredName(); beforeValue(); out.write(value ? "true" : "false"); return this; } /** * Encodes {@code value}. * * @return this writer. */ public MojangsonWriter value(Boolean value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); beforeValue(); out.write(value ? "true" : "false"); return this; } /** * Encodes {@code value}. * * @param value a finite value. May not be {@link Double#isNaN() NaNs} or {@link * Double#isInfinite() infinities}. * @return this writer. */ public MojangsonWriter value(double value) throws IOException { writeDeferredName(); if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); } beforeValue(); out.append(Double.toString(value)); return this; } /** * Encodes {@code value}. * * @return this writer. */ public MojangsonWriter value(long value) throws IOException { writeDeferredName(); beforeValue(); out.write(Long.toString(value)); return this; } /** * Encodes {@code value}. * * @param value a finite value. May not be {@link Double#isNaN() NaNs} or {@link * Double#isInfinite() infinities}. * @return this writer. */ public MojangsonWriter value(Number value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); String string = value.toString(); if (!lenient && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); } beforeValue(); out.append(string); return this; } /** * Ensures all buffered data is written to the underlying {@link Writer} and flushes that writer. */ public void flush() throws IOException { if (stackSize == 0) { throw new IllegalStateException("MojangsonWriter is closed."); } out.flush(); } /** * Flushes and closes this writer and the underlying {@link Writer}. * * @throws IOException if the JSON document is incomplete. */ public void close() throws IOException { out.close(); int size = stackSize; if (size > 1 || size == 1 && stack[size - 1] != MojangsonScope.NONEMPTY_DOCUMENT) { throw new IOException("Incomplete document"); } stackSize = 0; } private void newline() throws IOException { if (indent == null) { return; } out.write('\n'); for (int i = 1, size = stackSize; i < size; i++) { out.write(indent); } } /** * Inserts any necessary separators and whitespace before a name. Also adjusts the stack to expect * the name's value. */ private void beforeName() throws IOException { int context = peek(); if (context == MojangsonScope.NONEMPTY_OBJECT) { // first in object out.write(','); } else if (context != MojangsonScope.EMPTY_OBJECT) { // not in an object! throw new IllegalStateException("Nesting problem."); } newline(); replaceTop(MojangsonScope.DANGLING_NAME); } /** * Inserts any necessary separators and whitespace before a literal value, inline array, or inline * object. Also adjusts the stack to expect either a closing bracket or another element. */ @SuppressWarnings("fallthrough") private void beforeValue() throws IOException { switch (peek()) { case MojangsonScope.NONEMPTY_DOCUMENT: if (!lenient) { throw new IllegalStateException( "JSON must have only one top-level value."); } // fall-through case MojangsonScope.EMPTY_DOCUMENT: // first in document replaceTop(MojangsonScope.NONEMPTY_DOCUMENT); break; case MojangsonScope.EMPTY_ARRAY: // first in array replaceTop(MojangsonScope.NONEMPTY_ARRAY); newline(); break; case MojangsonScope.NONEMPTY_ARRAY: // another in array out.append(','); newline(); break; case MojangsonScope.DANGLING_NAME: // value for name out.append(separator); replaceTop(MojangsonScope.NONEMPTY_OBJECT); break; default: throw new IllegalStateException("Nesting problem."); } } private void string(String value) throws IOException { boolean quotesNeeded = value.contains(" ") || value.isEmpty(); for (char c : value.toCharArray()) { if (c > 0x7a || (c > 0x39 && c < 0x41) || c < 0x30 || (c > 0x5a && c < 0x61)) { quotesNeeded = true; break; } } if (quotesNeeded) { // Mojangson uses lenient json out.write('\"'); } int last = 0; int length = value.length(); if (last < length) { out.write(value, last, length - last); } if (quotesNeeded) { out.write('\"'); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/mojangson/TagDeserializer.java ================================================ package dev.simplix.cirrus.common.mojangson; import com.google.gson.*; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import net.querz.nbt.io.SNBTUtil; import net.querz.nbt.tag.Tag; import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Type; @Slf4j public final class TagDeserializer implements JsonDeserializer> { private static final Gson GSON = new GsonBuilder().create(); @Override public Tag deserialize( @NonNull JsonElement json, @NonNull Type typeOfT, @NonNull JsonDeserializationContext context) throws JsonParseException { if (!json.isJsonObject()) { throw new IllegalArgumentException("Expected json object!"); } StringWriter stringWriter = new StringWriter(); try { GSON.toJson(json, new MojangsonWriter(stringWriter)); return SNBTUtil.fromSNBT(stringWriter.toString()); } catch (IOException e) { log.error("Something went wrong while parsing SNBT string: " + stringWriter.toString()); throw new RuntimeException(e); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/mojangson/TagSerializer.java ================================================ package dev.simplix.cirrus.common.mojangson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import lombok.NonNull; import net.querz.nbt.io.SNBTUtil; import net.querz.nbt.tag.Tag; import java.io.IOException; import java.lang.reflect.Type; public final class TagSerializer implements JsonSerializer> { @Override public JsonElement serialize( @NonNull Tag src, @NonNull Type typeOfSrc, @NonNull JsonSerializationContext context) { try { String json = SNBTUtil.toSNBT(src); return JsonParser.parseString(json); } catch (IOException e) { throw new RuntimeException(e); } } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/util/ColorUtils.java ================================================ package dev.simplix.cirrus.common.util; import lombok.experimental.UtilityClass; import java.awt.*; import java.util.ArrayList; import java.util.List; @UtilityClass public class ColorUtils { public List colorsInBetween(final Color first, final Color second, final double step) { final double diffBlue = (second.getBlue() - first.getBlue()) / step; final double diffGreen = (second.getGreen() - first.getGreen()) / step; final double diffRed = (second.getRed() - first.getRed()) / step; final List list = new ArrayList<>(); for (int i = 1; i <= step; ++i) { list.add( new Color( (int) Math.round(first.getRed() + diffRed * i), (int) Math.round(first.getGreen() + diffGreen * i), (int) Math.round(first.getBlue() + diffBlue * i) ) ); } return list; } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/util/Colors.java ================================================ package dev.simplix.cirrus.common.util; import lombok.experimental.UtilityClass; import java.awt.*; @UtilityClass public class Colors { public final Color DARK_BLUE = new Color(0x0000AA); public final Color DARK_GREEN = new Color(0x00AA00); public final Color DARK_AQUA = new Color(0x00AAAA); public final Color DARK_RED = new Color(0xAA0000); public final Color DARK_PURPLE = new Color(0xAA00AA); public final Color GOLD = new Color(0xFFAA00); public final Color GRAY = new Color(0xAAAAAA); public final Color DARK_GRAY = new Color(0x555555); public final Color BLUE = new Color(0x5555FF); public final Color GREEN = new Color(0x55FF55); public final Color AQUA = new Color(0x55FFFF); public final Color RED = new Color(0xFF5555); public final Color LIGHT_PURPLE = new Color(0xFF55FF); public final Color YELLOW = new Color(0xFFFF55); public final Color WHITE = new Color(0xFFFFFF); } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/util/InventoryContentMap.java ================================================ package dev.simplix.cirrus.common.util; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import lombok.NonNull; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; public class InventoryContentMap implements ConcurrentMap { private final Map value = new ConcurrentHashMap<>(); // Delegate methods @Override public int size() { return this.value.size(); } @Override public boolean isEmpty() { return this.value.isEmpty(); } @Override public boolean containsKey(@NonNull Object key) { return this.value.containsKey(key); } @Override public boolean containsValue(@NonNull Object value) { return this.value.containsValue(value); } @Override public InventoryMenuItemWrapper get(@NonNull Object key) { return this.value.get(key); } @Nullable @Override public InventoryMenuItemWrapper put(@NonNull Integer key, @NonNull InventoryMenuItemWrapper value) { return this.value.put(key, value); } @Override public InventoryMenuItemWrapper remove(Object key) { return this.value.remove(key); } @Override public void putAll(@NotNull Map m) { this.value.putAll(m); } @Override public void clear() { this.value.clear(); } @NotNull @Override public Set keySet() { return this.value.keySet(); } @NotNull @Override public Collection values() { return this.value.values(); } @NotNull @Override public Set> entrySet() { return this.value.entrySet(); } @Override public boolean equals(Object obj) { return this.value.equals(obj); } @Override public int hashCode() { return this.value.hashCode(); } @Override public InventoryMenuItemWrapper getOrDefault(Object key, InventoryMenuItemWrapper defaultValue) { return this.value.getOrDefault(key, defaultValue); } @Override public void forEach(BiConsumer action) { this.value.forEach(action); } @Override public void replaceAll(BiFunction function) { this.value.replaceAll(function); } @Override public InventoryMenuItemWrapper putIfAbsent(Integer key, InventoryMenuItemWrapper value) { return this.value.putIfAbsent(key, value); } @Override public boolean remove(Object key, Object value) { return this.value.remove(key, value); } @Override public boolean replace( Integer key, InventoryMenuItemWrapper oldValue, InventoryMenuItemWrapper newValue) { return this.value.replace(key, oldValue, newValue); } @Override public InventoryMenuItemWrapper replace(Integer key, InventoryMenuItemWrapper value) { return this.value.replace(key, value); } @Override public InventoryMenuItemWrapper computeIfAbsent( Integer key, @NotNull Function mappingFunction) { return this.value.computeIfAbsent(key, mappingFunction); } @Override public InventoryMenuItemWrapper computeIfPresent( Integer key, @NotNull BiFunction remappingFunction) { return this.value.computeIfPresent(key, remappingFunction); } @Override public InventoryMenuItemWrapper compute( Integer key, @NotNull BiFunction remappingFunction) { return this.value.compute(key, remappingFunction); } @Override public InventoryMenuItemWrapper merge( Integer key, @NotNull InventoryMenuItemWrapper value, @NotNull BiFunction remappingFunction) { return this.value.merge(key, value, remappingFunction); } } ================================================ FILE: cirrus-common/src/main/java/dev/simplix/cirrus/common/util/SafeRunnable.java ================================================ package dev.simplix.cirrus.common.util; public interface SafeRunnable { void run() throws Throwable; } ================================================ FILE: cirrus-common/src/main/resources/cirrus/MenuConfiguration.json ================================================ { "title": { "en": "§bCirrus Menu", "de": "§bCirrus Menü" }, "type": "GENERIC_9X4", "placeholderItem": { "itemType": "GRAY_STAINED_GLASS_PANE", "displayName": { "en": "§0", "de": "§0" }, "lore": { "en": [], "de": [] }, "amount": 1, "slots": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 27, 28, 29, 30, 31, 32, 33, 34, 35 ] }, "reservedSlots": [], "items": [ { "itemType": "PLAYER_HEAD", "displayName": { "en": "§6Example Item", "de": "§6Beispielitem" }, "lore": { "en": [ "§7Hello §6{viewer}§7,", "§7this is an example item to show", "§7how Cirrus menus and items are configured." ], "de": [ "§7Hallo §6{viewer}§7,", "§7das ist ein Beispiel, um zu zeigen", "§7wie man Cirrus Menüs und Items konfiguriert." ] }, "amount": 1, "actionHandler": "noAction", "actionArguments": [], "slots": [ 13 ], "nbt": { "SkullOwner": "Exceptionflug" } } ] } ================================================ FILE: cirrus-common/src/main/resources/cirrus/MultiPageMenuConfiguration.json ================================================ { "title": { "en": "§bCirrus Menu {page} / {pageCount}", "de": "§bCirrus Menü {page} / {pageCount}" }, "type": "GENERIC_9X6", "placeholderItem": { "itemType": "GRAY_STAINED_GLASS_PANE", "displayName": { "en": "§0", "de": "§0" }, "lore": { "en": [], "de": [] }, "amount": 1, "slots": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 26, 27, 35, 36, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 ] }, "reservedSlots": [], "nextPageItem": { "itemType": "LIME_STAINED_GLASS_PANE", "displayName": { "en": "§aNext page", "de": "§aNächste Seite" }, "lore": { "en": [], "de": [] }, "amount": 1, "slots": [ 17, 26, 35, 44 ] }, "previousPageItem": { "itemType": "LIME_STAINED_GLASS_PANE", "displayName": { "en": "§cPrevious page", "de": "§cVorherige Seite" }, "lore": { "en": [], "de": [] }, "amount": 1, "slots": [ 9, 18, 27, 36 ] }, "items": [] } ================================================ FILE: cirrus-common/src/test/java/dev/simplix/cirrus/common/tests/SnbtGsonTest.java ================================================ package dev.simplix.cirrus.common.tests; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import dev.simplix.cirrus.common.mojangson.TagDeserializer; import dev.simplix.cirrus.common.mojangson.TagSerializer; import net.querz.nbt.tag.CompoundTag; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public final class SnbtGsonTest { private final Gson gson = new GsonBuilder() .registerTypeAdapter(CompoundTag.class, new TagSerializer()) .registerTypeAdapter(CompoundTag.class, new TagDeserializer()) .create(); // @Test public void test() { CompoundTag display = new CompoundTag(); display.putInt("integer", 134); display.putBoolean("boolean", true); display.putFloat("float", 24934.3F); display.putDouble("double", 9999.21348D); display.putShort("short", (short) 12); display.putByte("byte", (byte) 3); display.putString("string", "This is a string"); CompoundTag compoundTag = new CompoundTag(); compoundTag.put("display", display); String serialized = gson.toJson(compoundTag, CompoundTag.class); CompoundTag deserialized = gson.fromJson(serialized, CompoundTag.class); Assertions.assertEquals(compoundTag, deserialized); System.out.println("Cirrus SNBT over Gson - OK"); } } ================================================ FILE: cirrus-common/src/test/java/dev/simplix/cirrus/common/tests/SnbtTest.java ================================================ package dev.simplix.cirrus.common.tests; import net.querz.nbt.io.SNBTUtil; import net.querz.nbt.tag.CompoundTag; import net.querz.nbt.tag.Tag; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.IOException; public final class SnbtTest { @Test public void test() throws IOException { CompoundTag display = new CompoundTag(); display.putInt("integer", 134); display.putBoolean("boolean", true); display.putFloat("float", 24934.3F); display.putDouble("double", 9999.21348D); display.putShort("short", (short) 12); display.putByte("byte", (byte) 3); CompoundTag compoundTag = new CompoundTag(); compoundTag.put("display", display); String mojangson = SNBTUtil.toSNBT(compoundTag); Tag after = SNBTUtil.fromSNBT(mojangson); Assertions.assertEquals(compoundTag, after); System.out.println("Querz SNBT - OK"); } } ================================================ FILE: cirrus-spigot/pom.xml ================================================ 4.0.0 dev.simplix.cirrus cirrus 2.0.0 cirrus-spigot ${cirrus.version} org.spigotmc spigot-api 1.19-R0.1-SNAPSHOT provided org.spigotmc spigot-api 1.8.8-R0.1-SNAPSHOT provided dev.simplix.cirrus cirrus-common ${cirrus.version} compile dev.simplix.cirrus cirrus-spigot-modern ${cirrus.version} compile dev.simplix protocolize-api 2.1.0 compile org.slf4j slf4j-api 1.8.0-alpha2 provided ${project.name}-${project.version} src/main/resources true org.apache.maven.plugins maven-shade-plugin 3.0.0 package shade false org.apache.maven.plugins maven-compiler-plugin 8 8 org.apache.maven.plugins maven-source-plugin 3.0.1 attach-sources deploy jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.0.1 none attach-javadocs jar ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/CirrusSpigot.java ================================================ package dev.simplix.cirrus.spigot; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.effect.MenuAnimator; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.item.ProtocolizeMenuItemWrapper; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.spigot.converters.*; import dev.simplix.cirrus.spigot.listener.InventoryListener; import dev.simplix.cirrus.spigot.menubuilder.SpigotMenuBuilder; import dev.simplix.cirrus.spigot.util.BungeeCordComponentConverterProvider; import dev.simplix.cirrus.spigot.util.OtherModuleProvider; import dev.simplix.cirrus.spigot.util.ReflectionClasses; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.api.providers.ComponentConverterProvider; import dev.simplix.protocolize.api.providers.ModuleProvider; import dev.simplix.protocolize.data.ItemType; import dev.simplix.protocolize.data.inventory.InventoryType; import lombok.extern.slf4j.Slf4j; import net.querz.nbt.tag.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.material.MaterialData; import org.bukkit.plugin.java.JavaPlugin; import java.util.UUID; /** * Date: 18.09.2021 * * @author Exceptionflug */ @Slf4j public class CirrusSpigot { private static JavaPlugin plugin; public static void init(JavaPlugin plugin) { if (CirrusSpigot.plugin != null) { return; } CirrusSpigot.plugin = plugin; Cirrus.registerService(MenuBuilder.class, new SpigotMenuBuilder()); Bukkit.getPluginManager().registerEvents(new InventoryListener(), plugin); Protocolize.registerService(ComponentConverterProvider.class, new BungeeCordComponentConverterProvider()); Protocolize.registerService(ModuleProvider.class, new OtherModuleProvider()); registerConverters(); } private static void registerConverters() { try { // Players Converters.register( Player.class, PlayerWrapper.class, new PlayerConverter()); Converters.register(UUID.class, PlayerWrapper.class, o -> Bukkit.getPlayer((UUID) o)); // Items Converters.register( // Protocolize ----> Bukkit ItemStack.class, org.bukkit.inventory.ItemStack.class, new ProtocolizeItemStackConverter()); Converters.register( // Bukkit ----> Protocolize org.bukkit.inventory.ItemStack.class, ItemStack.class, new BukkitItemStackConverter()); Converters.register( ItemStack.class, MenuItemWrapper.class, o -> new ProtocolizeMenuItemWrapper( (dev.simplix.protocolize.api.item.ItemStack) o)); Converters.register(ItemType.class, MaterialData.class, new ItemTypeMaterialDataConverter()); Converters.register(MaterialData.class, ItemType.class, new MaterialDataItemTypeConverter()); Converters.register( CirrusItem.class, InventoryMenuItemWrapper.class, new ItemModelConverter()); Converters.register( InventoryType.class, org.bukkit.event.inventory.InventoryType.class, new SpigotInventoryTypeConverter()); Converters.register( ClickType.class, dev.simplix.protocolize.api.ClickType.class, new SpigotClickTypeConverter()); // NBT Converters.register( // Querz ----> NMS CompoundTag.class, ReflectionClasses.nbtTagCompound(), new QuerzNbtNmsNbtConverter()); Converters.register( // NMS ----> Querz ReflectionClasses.nbtTagCompound(), CompoundTag.class, new NmsNbtQuerzNbtConverter()); } catch (Exception exception) { log.error("Cannot register cirrus converters", exception); } Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, () -> { if (!MenuAnimator.isEmpty()) { MenuAnimator.updateAll(); } }, 2, 2); } public static JavaPlugin plugin() { if (plugin == null) { throw new IllegalStateException("Cirrus is not initialized. Please call CirrusSpigot#init during onEnable."); } return plugin; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/SpigotPlayerWrapper.java ================================================ package dev.simplix.cirrus.spigot; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.spigot.util.ProtocolVersionUtil; import dev.simplix.cirrus.spigot.util.ProtocolVersions; import lombok.NonNull; import org.bukkit.entity.Player; import java.util.UUID; public class SpigotPlayerWrapper implements PlayerWrapper { private final Player handle; public SpigotPlayerWrapper(@NonNull Player handle) { this.handle = handle; } @Override public void sendMessage(@NonNull String msg) { this.handle.sendMessage(msg); } @Override public void closeInventory() { this.handle.closeInventory(); } @Override public boolean hasPermission(@NonNull String permission) { return this.handle.hasPermission(permission); } @Override public UUID uniqueId() { return this.handle.getUniqueId(); } @Override public String name() { return this.handle.getName(); } @Override public T handle() { return (T) this.handle; } @Override public int protocolVersion() { return Math.min(ProtocolVersionUtil.serverProtocolVersion(), ProtocolVersions.MINECRAFT_1_17_1); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/BukkitItemStackConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.spigot.util.ReflectionClasses; import dev.simplix.cirrus.spigot.util.ReflectionUtil; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import net.querz.nbt.tag.CompoundTag; import org.bukkit.inventory.ItemStack; public class BukkitItemStackConverter implements Converter { private static Class craftItemStackClass; private static Class itemStackNMSClass; static { try { craftItemStackClass = ReflectionUtil.getClass("{obc}.inventory.CraftItemStack"); itemStackNMSClass = ReflectionClasses.itemStackClass(); } catch (Exception exception) { exception.printStackTrace(); } } @Override public dev.simplix.protocolize.api.item.ItemStack convert(@NonNull ItemStack src) { try { dev.simplix.protocolize.api.item.ItemStack out = new dev.simplix.protocolize.api.item.ItemStack( Converters.convert(src.getData(), ItemType.class), src.getAmount(), src.getDurability()); Object handle = ReflectionUtil.fieldValue(craftItemStackClass, src, "handle"); out.nbtData(Converters.convert( itemStackNMSClass.getMethod("getTag").invoke(handle), CompoundTag.class)); return out; } catch (Throwable throwable) { throwable.printStackTrace(); return null; } } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/ItemModelConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.protocolize.api.item.ItemStack; import lombok.NonNull; public class ItemModelConverter implements Converter { @Override public InventoryMenuItemWrapper convert(@NonNull CirrusItem model) { ItemStack itemStack = new ItemStack(model.itemType(), model.amount(), model.durability()); itemStack.nbtData(model.nbt()); itemStack.displayName(model.displayName()); itemStack.lore(model.lore(), true); return InventoryMenuItemWrapper.builder() .handle(Converters.convert(itemStack, MenuItemWrapper.class)) .actionArguments(model.actionArguments()) .actionHandler(model.actionHandler()) .build(); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/ItemTypeMaterialDataConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.spigot.util.ProtocolVersionUtil; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.mapping.ProtocolIdMapping; import dev.simplix.protocolize.api.providers.MappingProvider; import dev.simplix.protocolize.api.util.ProtocolVersions; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import org.bukkit.Material; import org.bukkit.material.MaterialData; public class ItemTypeMaterialDataConverter implements Converter { private final MappingProvider mappingProvider = Protocolize.mappingProvider(); @Override public MaterialData convert(@NonNull ItemType src) { ProtocolIdMapping mapping = this.mappingProvider.mapping(src, ProtocolVersionUtil.serverProtocolVersion()); if (mapping==null) { return null; } if (ProtocolVersionUtil.serverProtocolVersion() >= ProtocolVersions.MINECRAFT_1_13) { return new MaterialData(Material.valueOf(src.name())); } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/MaterialDataItemTypeConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import com.google.common.collect.Multimap; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.spigot.util.ProtocolVersionUtil; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.mapping.ProtocolIdMapping; import dev.simplix.protocolize.api.providers.MappingProvider; import dev.simplix.protocolize.api.util.ProtocolVersions; import dev.simplix.protocolize.data.ItemType; import dev.simplix.protocolize.data.mapping.LegacyItemProtocolIdMapping; import lombok.NonNull; import org.bukkit.material.MaterialData; public class MaterialDataItemTypeConverter implements Converter { private final MappingProvider mappingProvider = Protocolize.mappingProvider(); @Override public ItemType convert(@NonNull MaterialData src) { // Modern versioning if (ProtocolVersionUtil.serverProtocolVersion() >= ProtocolVersions.MINECRAFT_1_14) { return ItemType.valueOf(src.getItemType().name().replace("LEGACY_", "")); } // Deprecated Legacy versioning Multimap mappings = this.mappingProvider.mappings(ItemType.class, ProtocolVersionUtil.serverProtocolVersion()); for (ItemType type : mappings.keySet()) { for (ProtocolIdMapping mapping : mappings.get(type)) { if (mapping instanceof LegacyItemProtocolIdMapping) { if (mapping.id() == src.getItemTypeId() && ((LegacyItemProtocolIdMapping) mapping).data() == src.getData()) { return type; } } } } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/NmsNbtQuerzNbtConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.spigot.util.ReflectionClasses; import lombok.NonNull; import net.querz.nbt.io.NBTInputStream; import net.querz.nbt.tag.CompoundTag; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Method; public class NmsNbtQuerzNbtConverter implements Converter { private static Method nbtCompressedStreamToolAMethod; static { try { nbtCompressedStreamToolAMethod = ReflectionClasses.nbtCompressedStreamTools() .getMethod("a", ReflectionClasses.nbtTagCompound(), OutputStream.class); } catch (final Exception exception) { exception.printStackTrace(); } } @Override public CompoundTag convert(@NonNull Object src) { byte[] data = null; try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { nbtCompressedStreamToolAMethod.invoke(null, src, byteArrayOutputStream); data = byteArrayOutputStream.toByteArray(); } catch (final Exception exception) { exception.printStackTrace(); } try (final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) { return (CompoundTag) new NBTInputStream(byteArrayInputStream).readTag(99).getTag(); } catch (final IOException ioException) { ioException.printStackTrace(); } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/PlayerConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.spigot.SpigotPlayerWrapper; import lombok.NonNull; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; public final class PlayerConverter implements Converter { @Override public PlayerWrapper convert(@NonNull @NotNull Player proxiedPlayer) { return new SpigotPlayerWrapper(proxiedPlayer); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/ProtocolizeItemStackConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import dev.simplix.cirrus.common.Utils; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.spigot.util.ProtocolVersionUtil; import dev.simplix.cirrus.spigot.util.ReflectionClasses; import dev.simplix.cirrus.spigot.util.ReflectionUtil; import dev.simplix.protocolize.api.item.ItemStack; import lombok.NonNull; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.chat.ComponentSerializer; import net.querz.nbt.tag.*; import org.bukkit.Material; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.material.MaterialData; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import static dev.simplix.protocolize.api.util.ProtocolVersions.MINECRAFT_1_13; import static dev.simplix.protocolize.api.util.ProtocolVersions.MINECRAFT_1_14; public class ProtocolizeItemStackConverter implements Converter { private static Class craftItemStackClass; private static Class nbtTagCompoundClass; private static Class itemStackNMSClass; private static Method nmsCopyMethod; private static Method bukkitCopyMethod; private static Method setTagMethod; static { try { craftItemStackClass = ReflectionUtil.getClass("{obc}.inventory.CraftItemStack"); nbtTagCompoundClass = ReflectionClasses.nbtTagCompound(); itemStackNMSClass = ReflectionClasses.itemStackClass(); nmsCopyMethod = craftItemStackClass.getMethod( "asNMSCopy", org.bukkit.inventory.ItemStack.class); bukkitCopyMethod = craftItemStackClass.getMethod("asBukkitCopy", itemStackNMSClass); } catch (Exception exception) { exception.printStackTrace(); } } @Override public org.bukkit.inventory.ItemStack convert(@NonNull ItemStack src) { if (src.itemType() == null) { return null; } if (src.itemType() == null) { return new org.bukkit.inventory.ItemStack(Material.AIR); } MaterialData data = Converters.convert(src.itemType(), MaterialData.class); org.bukkit.inventory.ItemStack out; if (ProtocolVersionUtil.serverProtocolVersion() < MINECRAFT_1_13) { out = new org.bukkit.inventory.ItemStack( data.getItemType(), src.amount(), src.durability(), data.getData()); } else { out = new org.bukkit.inventory.ItemStack( data.getItemType(), src.amount(), src.durability()); } if (src.nbtData() == null) { src.nbtData(new CompoundTag()); } String textureHashToInsert = null; if (src.nbtData() != null) { CompoundTag tag = src.nbtData(); if (tag.containsKey("SkullOwner") && tag.get("SkullOwner") instanceof CompoundTag) { final CompoundTag skullOwnerTag = tag.getCompoundTag("SkullOwner"); final Tag propertiesRaw = skullOwnerTag.get("Properties"); if (propertiesRaw instanceof CompoundTag) { try { final ListTag textures = (ListTag) ((CompoundTag) propertiesRaw) .getListTag("textures"); textureHashToInsert = textures.get(0).getString("Value"); } catch (final Exception ignored) { } } } } writeDataToNbt(src); // Finalizing the itemstack by inserting nbt data & hiding attributes try { Object nmsItemStack = nmsCopyMethod.invoke(null, out); if (src.nbtData() != null) { try { Method setTag = method(); ; final CompoundTag nbtTag = src.nbtData().clone(); if (textureHashToInsert != null) { nbtTag.remove("SkullOwner"); } setTag.invoke(nmsItemStack, Converters.convert(nbtTag, nbtTagCompoundClass)); } catch (Throwable throwable) { throwable.printStackTrace(); } } final org.bukkit.inventory.ItemStack itemStackCopy = (org.bukkit.inventory.ItemStack) bukkitCopyMethod .invoke(null, nmsItemStack); mutateMetaDataToHideAttributes(itemStackCopy); if (textureHashToInsert == null) { return itemStackCopy; } final SkullMeta meta = (SkullMeta) itemStackCopy.getItemMeta(); mutateItemMetaForTextureHash(meta, textureHashToInsert); itemStackCopy.setItemMeta(meta); return itemStackCopy; } catch (final Exception exception) { exception.printStackTrace(); // Setting nbt to nms item is also pain in the ass } return out; } private Method method() throws NoSuchMethodException { if (setTagMethod != null) { return setTagMethod; } Method setTag; try { setTag = itemStackNMSClass.getMethod("setTag", nbtTagCompoundClass); } catch (NoSuchMethodException e) { setTag = itemStackNMSClass.getDeclaredMethod("setTagClone", nbtTagCompoundClass); setTag.setAccessible(true); } return setTagMethod = setTag; } private void mutateMetaDataToHideAttributes(org.bukkit.inventory.ItemStack out) { try { final ItemMeta itemMeta = out.getItemMeta(); itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); itemMeta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); itemMeta.addItemFlags(ItemFlag.HIDE_DESTROYS); itemMeta.addItemFlags(ItemFlag.HIDE_PLACED_ON); itemMeta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); out.setItemMeta(itemMeta); } catch (Throwable ignored) { } } private GameProfile makeProfile(@NonNull String textureHash) { // random uuid based on the textureHash string UUID id = new UUID( textureHash.substring(textureHash.length() - 20).hashCode(), textureHash.substring(textureHash.length() - 10).hashCode() ); GameProfile profile = new GameProfile(id, "Player"); profile.getProperties().put("textures", new Property("textures", textureHash)); return profile; } private void mutateItemMetaForTextureHash(SkullMeta meta, String textureHash) { try { Method metaSetProfileMethod = meta .getClass() .getDeclaredMethod("setProfile", GameProfile.class); metaSetProfileMethod.setAccessible(true); metaSetProfileMethod.invoke(meta, makeProfile(textureHash)); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException reflectiveOperationException) { // if in an older API where there is no setProfile method, // we set the profile field directly. try { Field profileField = meta.getClass().getDeclaredField("profile"); profileField.setAccessible(true); profileField.set(meta, makeProfile(textureHash)); } catch (NoSuchFieldException | IllegalAccessException exception) { exception.printStackTrace(); } } } private void writeDataToNbt(@NonNull ItemStack stack) { if (stack.displayName() != null) { if (ProtocolVersionUtil.serverProtocolVersion() >= MINECRAFT_1_13) { stack.nbtData().put("Damage", new IntTag(stack.durability())); final BaseComponent[] baseComponents = stack.displayName(); Utils.removeItalic(baseComponents); setDisplayNameTag(stack.nbtData(), ComponentSerializer.toString(baseComponents)); } else { setDisplayNameTag(stack.nbtData(), TextComponent.toLegacyText(stack.displayName())); } } if (stack.lore() != null) { setLoreTag(stack.nbtData(), stack.lore(), ProtocolVersionUtil.serverProtocolVersion()); } } private void setDisplayNameTag(@NonNull CompoundTag nbtData, @NonNull String name) { if (name == null) { return; } CompoundTag display = (CompoundTag) nbtData.get("display"); if (display == null) { display = new CompoundTag(); } final StringTag tag = new StringTag(name); display.put("Name", tag); nbtData.put("display", display); } private void setLoreTag( @NonNull CompoundTag nbtData, @NonNull List lore, int protocolVersion) { if (lore == null) { return; } CompoundTag display = (CompoundTag) nbtData.get("display"); if (display == null) { display = new CompoundTag(); } if (protocolVersion < MINECRAFT_1_14) { final ListTag tag = new ListTag<>(StringTag.class); tag.addAll(lore.stream().map(i -> new StringTag(TextComponent.toLegacyText(i))).collect( Collectors.toList())); display.put("Lore", tag); nbtData.put("display", display); } else { final ListTag tag = new ListTag<>(StringTag.class); tag.addAll(lore.stream().map(components -> { for (BaseComponent component : components) { if (!component.isItalic()) { component.setItalic(false); } } return new StringTag(ComponentSerializer.toString(components)); }).collect(Collectors.toList())); display.put("Lore", tag); nbtData.put("display", display); } } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/QuerzNbtNmsNbtConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.spigot.util.ReflectionClasses; import lombok.NonNull; import net.querz.nbt.io.NBTOutputStream; import net.querz.nbt.tag.CompoundTag; import org.jetbrains.annotations.NotNull; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.util.zip.GZIPOutputStream; public class QuerzNbtNmsNbtConverter implements Converter { private static Method nbtCompressedStreamToolAMethod; static { try { nbtCompressedStreamToolAMethod = ReflectionClasses .nbtCompressedStreamTools() .getMethod("a", InputStream.class); } catch (final Exception e) { e.printStackTrace(); } } @Override public Object convert(@NonNull @NotNull CompoundTag src) { byte[] data = null; try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); new NBTOutputStream(gzipOutputStream).writeTag(src, 99); gzipOutputStream.close(); data = byteArrayOutputStream.toByteArray(); } catch (IOException ioException) { ioException.printStackTrace(); } try (final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) { return nbtCompressedStreamToolAMethod.invoke(null, byteArrayInputStream); } catch (Exception exception) { exception.printStackTrace(); } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/SpigotClickTypeConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import lombok.NonNull; import org.bukkit.event.inventory.ClickType; import org.jetbrains.annotations.NotNull; public class SpigotClickTypeConverter implements Converter { @Override public dev.simplix.protocolize.api.ClickType convert(@NonNull @NotNull ClickType src) { switch (src) { case LEFT: return dev.simplix.protocolize.api.ClickType.LEFT_CLICK; case RIGHT: return dev.simplix.protocolize.api.ClickType.RIGHT_CLICK; case DROP: return dev.simplix.protocolize.api.ClickType.DROP; case MIDDLE: return dev.simplix.protocolize.api.ClickType.CREATIVE_MIDDLE_CLICK; case NUMBER_KEY: return dev.simplix.protocolize.api.ClickType.NUMBER_BUTTON_1; case SHIFT_LEFT: return dev.simplix.protocolize.api.ClickType.SHIFT_LEFT_CLICK; case SHIFT_RIGHT: return dev.simplix.protocolize.api.ClickType.SHIFT_RIGHT_CLICK; case CONTROL_DROP: return dev.simplix.protocolize.api.ClickType.DROP_ALL; case DOUBLE_CLICK: return dev.simplix.protocolize.api.ClickType.DOUBLE_CLICK; case WINDOW_BORDER_LEFT: return dev.simplix.protocolize.api.ClickType.LEFT_CLICK_OUTSIDE_INVENTORY_HOLDING_NOTHING; case WINDOW_BORDER_RIGHT: return dev.simplix.protocolize.api.ClickType.RIGHT_CLICK_OUTSIDE_INVENTORY_HOLDING_NOTHING; } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/converters/SpigotInventoryTypeConverter.java ================================================ package dev.simplix.cirrus.spigot.converters; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.protocolize.data.inventory.InventoryType; import lombok.NonNull; public class SpigotInventoryTypeConverter implements Converter { @Override public org.bukkit.event.inventory.InventoryType convert(@NonNull InventoryType src) { switch (src) { case ANVIL: return org.bukkit.event.inventory.InventoryType.ANVIL; case BEACON: return org.bukkit.event.inventory.InventoryType.BEACON; case BREWING_STAND: return org.bukkit.event.inventory.InventoryType.BREWING; case CRAFTING: return org.bukkit.event.inventory.InventoryType.WORKBENCH; case GENERIC_3X3: return org.bukkit.event.inventory.InventoryType.DISPENSER; case ENCHANTMENT: return org.bukkit.event.inventory.InventoryType.ENCHANTING; case FURNACE: return org.bukkit.event.inventory.InventoryType.FURNACE; case HOPPER: return org.bukkit.event.inventory.InventoryType.HOPPER; case MERCHANT: return org.bukkit.event.inventory.InventoryType.MERCHANT; } if (src.name().startsWith("GENERIC")) { return org.bukkit.event.inventory.InventoryType.CHEST; } return null; } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/listener/InventoryListener.java ================================================ package dev.simplix.cirrus.spigot.listener; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.menu.AbstractMenu; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.model.Click; import lombok.extern.slf4j.Slf4j; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.InventoryView; import java.util.Map; @Slf4j public class InventoryListener implements Listener { private final MenuBuilder menuBuilder = Cirrus.getService(MenuBuilder.class); @EventHandler public void onDrag(InventoryDragEvent event) { InventoryView inventoryView = event.getWhoClicked().getOpenInventory(); if (event.getInventory() == null) { return; } Menu menu = this.menuBuilder.menuByHandle(inventoryView); if (menu == null) { return; } event.setCancelled(true); } @EventHandler public void onClick(InventoryClickEvent event) { InventoryView inventoryView = event.getWhoClicked().getOpenInventory(); if (event.getClickedInventory() == null) { return; } // Bukkit.broadcastMessage("Clicked inventoryView"); Menu menu = this.menuBuilder.menuByHandle(inventoryView); if (menu == null) { return; } // Bukkit.broadcastMessage("Clicked menu: " // + menu.getClass().getSimpleName() // + " @ slot " // + event.getSlot()); Container container; if (event.getRawSlot() > menu.topContainer().capacity() - 1) { container = menu.bottomContainer(); // Bukkit.broadcastMessage("Clicked bottom container"); } else { container = menu.topContainer(); // Bukkit.broadcastMessage("Clicked top container"); } InventoryMenuItemWrapper item = container.get(event.getRawSlot()); ClickType type = event.getClick(); if (item == null) { // Bukkit.broadcastMessage("Clicked nothing"); if (menu.customActionHandler() != null) { try { CallResult callResult = menu .customActionHandler() .handle(new Click(Converters.convert( type, dev.simplix.protocolize.api.ClickType.class), menu, null, event.getSlot())); event.setCancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (Exception ex) { event.setCancelled(true); menu.handleException(null, ex); } } return; } // Bukkit.broadcastMessage("Clicked " + item.displayName()); ActionHandler actionHandler = menu.actionHandler(item.actionHandler()); if (actionHandler == null) { event.setCancelled(true); return; } try { final CallResult callResult = actionHandler.handle(new Click( Converters.convert(type, dev.simplix.protocolize.api.ClickType.class), menu, item, event.getSlot())); event.setCancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (final Exception ex) { event.setCancelled(true); menu.handleException(actionHandler, ex); } } @EventHandler public void onQuit(PlayerQuitEvent event) { this.menuBuilder.destroyMenusOfPlayer(event.getPlayer().getUniqueId()); } @EventHandler public void onClose(InventoryCloseEvent inventoryCloseEvent) { InventoryView inventoryView = inventoryCloseEvent.getPlayer().getOpenInventory(); if (inventoryView == null) { return; } Menu menu = this.menuBuilder.menuByHandle(inventoryView); if (menu == null) { return; } ((Player) inventoryCloseEvent.getPlayer()).updateInventory(); Map.Entry lastBuild = this.menuBuilder.lastBuildOfPlayer(inventoryCloseEvent.getPlayer().getUniqueId()); if (lastBuild == null) { log.warn("[Cirrus] Exiting from unbuilt menu? Class = " + menu.getClass().getName() + ", Player = " + inventoryCloseEvent.getPlayer().getName()); menu.handleClose(false); this.menuBuilder.invalidate(menu); return; } if (((AbstractMenu) lastBuild.getKey()).internalId() == ((AbstractMenu) menu).internalId() && (System.currentTimeMillis() - lastBuild.getValue()) <= 55) { return; } menu.handleClose((System.currentTimeMillis() - lastBuild.getValue()) <= 55); this.menuBuilder.invalidate(menu); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/menubuilder/SpigotMenuBuilder.java ================================================ package dev.simplix.cirrus.spigot.menubuilder; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.common.menus.MultiPageMenu; import dev.simplix.cirrus.spigot.util.ProtocolVersionUtil; import dev.simplix.cirrus.spigot.util.ReflectionUtil; import dev.simplix.protocolize.api.util.ProtocolVersions; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.bukkit.Bukkit; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; import java.util.*; import java.util.Map.Entry; @Slf4j public final class SpigotMenuBuilder implements MenuBuilder { private static Constructor modernInventoryViewConstructor; static { try { if (ProtocolVersionUtil.serverProtocolVersion() > ProtocolVersions.MINECRAFT_1_13) { Class modernInventoryViewClass = SpigotMenuBuilder.class.getClassLoader() .loadClass("dev.simplix.cirrus.spigot.modern.ModernInventoryView"); modernInventoryViewConstructor = modernInventoryViewClass.getConstructor(Menu.class, Inventory.class, Inventory.class); } } catch (ReflectiveOperationException exception) { log.error("SpigotMenuBuilder won't work", exception); } } private final Map> buildMap = new LinkedHashMap<>(); private final List menus = new LinkedList<>(); @Override public T build(@Nullable T prebuild, @NonNull Menu menu) { boolean reopen = false; boolean register = prebuild == null; if (prebuild instanceof InventoryView) { InventoryView inventoryView = (InventoryView) prebuild; if (!inventoryView.getTitle().equals(menu.title()) || inventoryView.getTopInventory().getSize() != menu.inventoryType() .getTypicalSize(ProtocolVersionUtil.serverProtocolVersion()) || inventoryView.getTopInventory().getType() != Converters .convert(menu.inventoryType(), org.bukkit.event.inventory.InventoryType.class)) { prebuild = (T) makeView(menu); reopen = true; } } else { prebuild = (T) makeView(menu); } InventoryView view = (InventoryView) prebuild; buildContainer(view.getTopInventory(), menu.topContainer(), false); // buildContainer(view.getBottomInventory(), menu.bottomContainer(), true); this.buildMap.put( menu.player().uniqueId(), new AbstractMap.SimpleEntry<>(menu, System.currentTimeMillis())); if (register) { this.menus.add(menu); } if (reopen || menu instanceof MultiPageMenu) { open(menu.player(), prebuild); } return prebuild; } private void buildContainer(Inventory inventory, Container container, boolean bottom) { for (int i = 0; i < container.capacity(); i++) { InventoryMenuItemWrapper item = container.itemMap().get(i + container.baseSlot()); ItemStack currentStack = inventory.getItem(i); if (item == null) { if (currentStack != null) { if (bottom) { inventory.setItem( container.baseSlot() + container.capacity() - 1 - ( i + container.baseSlot()), null); } else { inventory.setItem(i, null); } } } if (item != null) { ItemStack bukkitItemStack = Converters.convert(item.handle(), ItemStack.class); if (currentStack == null) { if (item.handle() == null) { Bukkit.getLogger() .severe("InventoryItem's ItemStackWrapper is null @ slot " + i); continue; } if (bottom) { inventory.setItem( container.baseSlot() + container.capacity() - 1 - ( i + container.baseSlot()), bukkitItemStack); } else { inventory.setItem(i, bukkitItemStack); } } else { if (!currentStack.equals(bukkitItemStack)) { if (bottom) { inventory.setItem( container.baseSlot() + container.capacity() - 1 - ( i + container.baseSlot()), bukkitItemStack); } else { inventory.setItem(i, bukkitItemStack); } } } } } } private static boolean isChest(dev.simplix.protocolize.data.inventory.InventoryType type) { if (type == dev.simplix.protocolize.data.inventory.InventoryType.GENERIC_3X3) { return false; } else { return type.name().startsWith("GENERIC") || type.name().contains("CHEST"); } } private InventoryView makeView(Menu menu) { Inventory top; if (isChest(menu.inventoryType())) { top = Bukkit.createInventory( menu.player().handle(), menu.inventoryType().getTypicalSize(ProtocolVersionUtil.serverProtocolVersion()), menu.title()); } else { top = Bukkit.createInventory( menu.player().handle(), Converters .convert(menu.inventoryType(), org.bukkit.event.inventory.InventoryType.class), menu.title()); } Inventory bottom; if (menu.bottomContainer().itemMap().isEmpty()) { bottom = ((Player) menu.player().handle()).getInventory(); } else { bottom = createPlayerInventory(menu.player().handle()); } if (ProtocolVersionUtil.serverProtocolVersion() > ProtocolVersions.MINECRAFT_1_13) { return modernView(menu, top, bottom); } else { return legacyView(menu, top, bottom); } } private InventoryView modernView(Menu menu, Inventory top, Inventory bottom) { // We need to construct this class using reflection since referencing this class in code // would cause a VerifyError while loading the class on non-modern spigot versions. try { return (InventoryView) modernInventoryViewConstructor .newInstance(menu, top, bottom); } catch (Exception e) { log.error("Unable to construct ModernInventoryView", e); } return null; } private InventoryView legacyView(Menu menu, Inventory top, Inventory bottom) { return new InventoryView() { private final Inventory topInventory = top; private final Inventory bottomInventory = bottom; @Override public Inventory getTopInventory() { return this.topInventory; } @Override public Inventory getBottomInventory() { return this.bottomInventory; } @Override public HumanEntity getPlayer() { return menu.player().handle(); } @Override public InventoryType getType() { return Converters.convert( menu.inventoryType(), org.bukkit.event.inventory.InventoryType.class); } }; } private Inventory createPlayerInventory(Player player) { try { Class craftPlayerInventoryClass = ReflectionUtil.getClass("{obc}.inventory.CraftInventoryPlayer"); Class nmsPlayerInventoryClass = ReflectionUtil.getClass("{nms}.PlayerInventory"); Class nmsEntityHumanClass = ReflectionUtil.getClass("{nms}.EntityHuman"); Constructor nmsPlayerInventoryConstructor = nmsPlayerInventoryClass.getConstructor(nmsEntityHumanClass); Object nmsPlayerInventory = nmsPlayerInventoryConstructor.newInstance( nmsEntityHumanClass.cast(ReflectionUtil.nmsPlayer(player))); Constructor craftPlayerInventoryConstructor = craftPlayerInventoryClass.getConstructor(nmsPlayerInventoryClass); return (Inventory) craftPlayerInventoryConstructor.newInstance(nmsPlayerInventory); } catch (ReflectiveOperationException exception) { log.error("Cannot create player inventory", exception); } return null; } @Override public void open(@NonNull PlayerWrapper playerWrapper, @NonNull T inventoryImpl) { ((Player) playerWrapper.handle()).openInventory((InventoryView) inventoryImpl); } @Override public Menu menuByHandle(Object handle) { if (handle == null) { return null; } for (final Menu menu : this.menus) { if (menu.equals(handle)) { return menu; } } return null; } @Override public void destroyMenusOfPlayer(@NonNull UUID uniqueId) { this.menus.removeIf( wrapper -> ((Player) wrapper.player().handle()).getUniqueId().equals(uniqueId)); this.buildMap.remove(uniqueId); } @Override public Entry lastBuildOfPlayer(@NonNull UUID uniqueId) { return this.buildMap.get(uniqueId); } @Override public void invalidate(@NonNull Menu menu) { this.menus.remove(menu); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/menus/SpigotMenu.java ================================================ package dev.simplix.cirrus.spigot.menus; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.spigot.util.SpigotItemsUtils; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; public interface SpigotMenu extends Menu { default ItemType typeFromMaterial(@NonNull MaterialData material) { return SpigotItemsUtils.typeFromMaterial(material); } default ItemType typeFromMaterial(@NonNull Material material) { return SpigotItemsUtils.typeFromMaterial(material); } default MenuItemWrapper wrapBukkitItemStack(@NonNull ItemStack itemStack) { return SpigotItemsUtils.wrapBukkitItemStack(itemStack); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/BungeeCordComponentConverterProvider.java ================================================ package dev.simplix.cirrus.spigot.util; import dev.simplix.protocolize.api.ComponentConverter; import dev.simplix.protocolize.api.providers.ComponentConverterProvider; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.chat.ComponentSerializer; /** * Date: 24.08.2021 * * @author Exceptionflug */ public final class BungeeCordComponentConverterProvider implements ComponentConverterProvider { @Override public ComponentConverter platformConverter() { return BungeeCordComponentConverter.INSTANCE; } public static class BungeeCordComponentConverter implements ComponentConverter { static BungeeCordComponentConverter INSTANCE = new BungeeCordComponentConverter(); private BungeeCordComponentConverter() { } @Override public String toLegacyText(BaseComponent[] components) { return new TextComponent(components).toLegacyText(); } @Override public String toJson(BaseComponent[] components) { return ComponentSerializer.toString(components); } @Override public BaseComponent[] fromLegacyText(String legacyText) { return TextComponent.fromLegacyText("§r" + legacyText); } @Override public BaseComponent[] fromJson(String json) { return ComponentSerializer.parse(json); } } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/OtherModuleProvider.java ================================================ package dev.simplix.cirrus.spigot.util; import dev.simplix.protocolize.api.Platform; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.module.ProtocolizeModule; import dev.simplix.protocolize.api.providers.ModuleProvider; import lombok.Getter; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * Date: 23.08.2021 * * @author Exceptionflug */ @Slf4j(topic = "Protocolize") @Getter @Accessors(fluent = true) public final class OtherModuleProvider implements ModuleProvider { private final List modules = new ArrayList<>(); @Override public void registerModule(ProtocolizeModule module) { if (!supportedPlatform(module.supportedPlatforms())) { log.warn("Won't register module " + module.getClass().getName() + ": Only supports " + Arrays.toString(module.supportedPlatforms())); return; } modules.add(module); enableModule(module); } @Override public boolean moduleInstalled(String s) { return this.modules.stream().map(module -> module.getClass().getSimpleName()).collect(Collectors.toList()).contains(s); } @Override public ProtocolizeModule module(String s) { return this.modules.stream().filter(module -> module.getClass().getSimpleName().equalsIgnoreCase(s)).findFirst().orElse(null); } private boolean supportedPlatform(Platform[] supportedPlatforms) { for (Platform platform : supportedPlatforms) { if (Protocolize.platform() == platform) { return true; } } return false; } private void enableModule(ProtocolizeModule module) { module.registerMappings(Protocolize.mappingProvider()); module.registerPackets(Protocolize.protocolRegistration()); log.info("Enabled module " + module.getClass().getName()); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/ProtocolVersionUtil.java ================================================ package dev.simplix.cirrus.spigot.util; import java.lang.reflect.Field; import dev.simplix.protocolize.data.inventory.InventoryType; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public final class ProtocolVersionUtil { private static int protocolVersion; public static int serverProtocolVersion() { if (protocolVersion == 0) { protocolVersion = detectVersion(); } return protocolVersion; } private static int detectVersion() { String majorVersion = ReflectionUtil .serverVersion() .substring(1, ReflectionUtil.serverVersion().indexOf('_', 3)); try { Field field = dev.simplix.cirrus.spigot.util.ProtocolVersions.class.getField("MINECRAFT_" + majorVersion); return field.getInt(null); } catch (NoSuchFieldException e) { throw new RuntimeException("Cirrus is not compatible with server version " + ReflectionUtil.serverVersion()); } catch (IllegalAccessException e) { log.error("[Cirrus] Unable to detect protocol version", e); return ProtocolVersions.MINECRAFT_1_8; } } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/ProtocolVersions.java ================================================ package dev.simplix.cirrus.spigot.util; public class ProtocolVersions { public final static int MINECRAFT_1_8 = 47; public final static int MINECRAFT_1_9 = 107; public final static int MINECRAFT_1_9_1 = 108; public final static int MINECRAFT_1_9_2 = 109; public final static int MINECRAFT_1_9_3 = 110; public final static int MINECRAFT_1_9_4 = MINECRAFT_1_9_3; public final static int MINECRAFT_1_10 = 210; public final static int MINECRAFT_1_11 = 315; public final static int MINECRAFT_1_11_1 = 316; public final static int MINECRAFT_1_11_2 = MINECRAFT_1_11_1; public final static int MINECRAFT_1_12 = 335; public final static int MINECRAFT_1_12_1 = 338; public final static int MINECRAFT_1_12_2 = 340; public final static int MINECRAFT_1_13 = 393; public final static int MINECRAFT_1_13_1 = 401; public final static int MINECRAFT_1_13_2 = 404; public final static int MINECRAFT_1_14 = 477; public final static int MINECRAFT_1_14_1 = 480; public final static int MINECRAFT_1_14_2 = 485; public final static int MINECRAFT_1_14_3 = 490; public final static int MINECRAFT_1_14_4 = 498; public final static int MINECRAFT_1_15 = 573; public final static int MINECRAFT_1_15_1 = 575; public final static int MINECRAFT_1_15_2 = 578; public final static int MINECRAFT_1_16 = 735; public final static int MINECRAFT_1_16_1 = 736; public final static int MINECRAFT_1_16_2 = 751; public final static int MINECRAFT_1_16_3 = 753; public final static int MINECRAFT_1_16_4 = 754; public final static int MINECRAFT_1_16_5 = MINECRAFT_1_16_4; public final static int MINECRAFT_1_17 = 755; public final static int MINECRAFT_1_17_1 = 756; public final static int MINECRAFT_1_18 = 757; public final static int MINECRAFT_LATEST = MINECRAFT_1_18; } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/ReflectionClasses.java ================================================ package dev.simplix.cirrus.spigot.util; public class ReflectionClasses { public static Class itemStackClass() throws ClassNotFoundException { if (ReflectionUtil.hasNewPackageStructure()) { return ReflectionUtil .getClass("{nm}.world.item.ItemStack"); } else { return ReflectionUtil .getClass("{nms}.ItemStack"); } } public static Class nbtCompressedStreamTools() throws ClassNotFoundException { if (ReflectionUtil.hasNewPackageStructure()) { return ReflectionUtil .getClass("{nm}.nbt.NBTCompressedStreamTools"); } else { return ReflectionUtil .getClass("{nms}.NBTCompressedStreamTools"); } } public static Class nbtTagCompound() throws ClassNotFoundException { if (ReflectionUtil.hasNewPackageStructure()) { return ReflectionUtil .getClass("{nm}.nbt.NBTTagCompound"); } else { return ReflectionUtil .getClass("{nms}.NBTTagCompound"); } } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/ReflectionUtil.java ================================================ package dev.simplix.cirrus.spigot.util; import com.mojang.authlib.GameProfile; import lombok.AccessLevel; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.AbstractMap; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public final class ReflectionUtil { private static final String EXCEPTION_OCCURRED = "Exception occurred"; private static final String GET_HANDLE = "getHandle"; private static final String PLAYER_CONNECTION = "playerConnection"; private static final String SEND_PACKET = "sendPacket"; private static final String NMS_PACKET = "{nms}.Packet"; private static final Map, String>, Field> CACHED_FIELDS = new HashMap<>(); private static final Map> CACHED_CLASSES = new HashMap<>(); public static boolean hasNewPackageStructure() { return ProtocolVersionUtil.serverProtocolVersion() >= ProtocolVersions.MINECRAFT_1_17; } public static Class getClass(String classname) throws ClassNotFoundException { String path = classname .replace( "{nm}", "net.minecraft" + ( hasNewPackageStructure() ? "" : "." + serverVersion())) .replace( "{nms}", "net.minecraft.server" + ( hasNewPackageStructure() ? "" : "." + serverVersion())) .replace("{obc}", "org.bukkit.craftbukkit." + serverVersion()); Class out = CACHED_CLASSES.get(path); if (out == null) { out = Class.forName(path); CACHED_CLASSES.put(path, out); } return out; } public static String serverVersion() { try { return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; } catch (Exception exception) { return "v1_17_1"; } } public static GameProfile gameProfile(@NonNull Player player) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { Object obcPlayer = obcPlayer(player); Class obcPlayerClass = obcPlayer.getClass(); return (GameProfile) obcPlayerClass.getMethod("getProfile").invoke(player); } public static Object nmsPlayer(@NonNull Player player) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method getHandle = player.getClass().getMethod(GET_HANDLE); return getHandle.invoke(player); } public static Object obcPlayer(@NonNull Player player) throws ClassNotFoundException { return getClass("{obc}.entity.CraftPlayer").cast(player); } public static Object nmsWorld(@NonNull World world) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method getHandle = world.getClass().getMethod(GET_HANDLE); return getHandle.invoke(world); } public static Object nmsScoreboard(@NonNull Scoreboard scoreboard) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method getHandle = scoreboard.getClass().getMethod(GET_HANDLE); return getHandle.invoke(scoreboard); } public static Object fieldValue(@NonNull Object instance, @NonNull String fieldName) throws IllegalAccessException { final Map.Entry, String> key = new AbstractMap.SimpleEntry<>( instance.getClass(), fieldName); final Field field = CACHED_FIELDS.computeIfAbsent(key, i -> { try { return instance.getClass().getDeclaredField(fieldName); } catch (final NoSuchFieldException e) { log.error(EXCEPTION_OCCURRED, e); } return null; }); if (field == null) { return null; } if (!field.isAccessible()) { field.setAccessible(true); } return field.get(instance); } public static T fieldValue(@NonNull Field field, @NonNull Object obj) { try { return (T) field.get(obj); } catch (Exception exception) { log.error(EXCEPTION_OCCURRED, exception); return null; } } public static Field field(@NonNull Class clazz, @NonNull String fieldName) throws NoSuchFieldException { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field; } public static void value(Object instance, String field, Object value) { try { Field f = instance.getClass().getDeclaredField(field); f.setAccessible(true); f.set(instance, value); } catch (Exception exception) { log.error(EXCEPTION_OCCURRED, exception); } } public static void value( @NonNull Class clazz, @NonNull Object instance, @NonNull String field, @NonNull Object value) { try { Field declaredField = clazz.getDeclaredField(field); declaredField.setAccessible(true); declaredField.set(instance, value); } catch (Exception e) { log.error(EXCEPTION_OCCURRED, e); } } public static void valueSubclass( @NonNull Class clazz, @NonNull Object instance, @NonNull String field, @NonNull Object value) { try { Field declaredField = clazz.getDeclaredField(field); declaredField.setAccessible(true); declaredField.set(instance, value); } catch (Exception e) { log.error(EXCEPTION_OCCURRED, e); } } public static void sendAllPacket(@NonNull Object packet) throws ReflectiveOperationException { for (Player p : Bukkit.getOnlinePlayers()) { Object nmsPlayer = nmsPlayer(p); Object connection = nmsPlayer.getClass().getField(PLAYER_CONNECTION).get(nmsPlayer); connection .getClass() .getMethod(SEND_PACKET, ReflectionUtil.getClass(NMS_PACKET)) .invoke(connection, packet); } } public static void sendListPacket(@NonNull List players, @NonNull Object packet) { try { for (String name : players) { Object nmsPlayer = nmsPlayer(Bukkit.getPlayer(name)); Object connection = nmsPlayer.getClass().getField(PLAYER_CONNECTION).get(nmsPlayer); connection .getClass() .getMethod(SEND_PACKET, ReflectionUtil.getClass(NMS_PACKET)) .invoke(connection, packet); } } catch (Exception exception) { log.error(EXCEPTION_OCCURRED, exception); } } public static void sendPlayerPacket(@NonNull Player player, @NonNull Object packet) throws ReflectiveOperationException { Object nmsPlayer = nmsPlayer(player); Object connection = nmsPlayer.getClass().getField(PLAYER_CONNECTION).get(nmsPlayer); connection .getClass() .getMethod(SEND_PACKET, ReflectionUtil.getClass(NMS_PACKET)) .invoke(connection, packet); } public static void listFields(@NonNull Object object) { log.info(object.getClass().getName() + " contains " + object .getClass() .getDeclaredFields().length + " declared fields."); log.info(object.getClass().getName() + " contains " + object .getClass() .getDeclaredClasses().length + " declared classes."); Field[] declaredFields = object.getClass().getDeclaredFields(); for (Field field : declaredFields) { field.setAccessible(true); try { log.info(field.getName() + " -> " + field.get(object)); } catch (IllegalArgumentException | IllegalAccessException exception) { log.error(EXCEPTION_OCCURRED, exception); } } } public static Object fieldValue( @NonNull Class superclass, @NonNull Object instance, @NonNull String fieldName) throws IllegalAccessException, NoSuchFieldException { Field field = superclass.getDeclaredField(fieldName); field.setAccessible(true); return field.get(instance); } } ================================================ FILE: cirrus-spigot/src/main/java/dev/simplix/cirrus/spigot/util/SpigotItemsUtils.java ================================================ package dev.simplix.cirrus.spigot.util; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.item.ProtocolizeMenuItemWrapper; import dev.simplix.protocolize.data.ItemType; import lombok.NonNull; import lombok.experimental.UtilityClass; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; @UtilityClass public class SpigotItemsUtils { public ItemType typeFromMaterial(@NonNull MaterialData material) { return Converters.convert(material, ItemType.class); } public ItemType typeFromMaterial(@NonNull Material material) { return ItemType.valueOf(material.name()); } public MenuItemWrapper wrapBukkitItemStack(@NonNull ItemStack itemStack) { dev.simplix.protocolize.api.item.ItemStack protocolizeStack = Converters.convert(itemStack, dev.simplix.protocolize.api.item.ItemStack.class); return new ProtocolizeMenuItemWrapper(protocolizeStack); } } ================================================ FILE: cirrus-spigot-example/pom.xml ================================================ 4.0.0 dev.simplix.cirrus cirrus 2.0.0 cirrus-spigot-example ${cirrus.version} cirrus-common dev.simplix.cirrus compile ${cirrus.version} cirrus-spigot dev.simplix.cirrus compile ${cirrus.version} org.spigotmc spigot-api 1.19-R0.1-SNAPSHOT provided ${project.name}-${project.version} src/main/resources true org.apache.maven.plugins maven-compiler-plugin 8 8 maven-shade-plugin 3.2.4 package shade ================================================ FILE: cirrus-spigot-example/src/main/java/dev/simplix/cirrus/spigot/example/CirrusExamplePlugin.java ================================================ package dev.simplix.cirrus.spigot.example; import dev.simplix.cirrus.spigot.CirrusSpigot; import dev.simplix.cirrus.spigot.example.commands.TestCommandExecutor; import org.bukkit.plugin.java.JavaPlugin; public class CirrusExamplePlugin extends JavaPlugin { @Override public void onEnable() { CirrusSpigot.init(this); getCommand("test").setExecutor(new TestCommandExecutor()); } } ================================================ FILE: cirrus-spigot-example/src/main/java/dev/simplix/cirrus/spigot/example/commands/TestCommandExecutor.java ================================================ package dev.simplix.cirrus.spigot.example.commands; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.impl.SimpleMultiPageMenuConfiguration; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.spigot.example.menus.ExampleMultiPageMenu; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class TestCommandExecutor implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String s, String[] args) { if (sender instanceof Player) { Player player = (Player) sender; final PlayerWrapper wrapper = Converters.getConverter(Player.class, PlayerWrapper.class).convert(player); new ExampleMultiPageMenu( wrapper, Cirrus.configurationFactory().loadFile( "plugins/Cirrus/example2.json", SimpleMultiPageMenuConfiguration.class)).open(); } return false; } } ================================================ FILE: cirrus-spigot-example/src/main/java/dev/simplix/cirrus/spigot/example/menus/ExampleMenu.java ================================================ package dev.simplix.cirrus.spigot.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.effects.RGBColorChangeAnimation; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.menu.AbstractConfigurableMenu; import dev.simplix.cirrus.common.model.CallResult; import java.awt.*; import java.util.Locale; public class ExampleMenu extends AbstractConfigurableMenu { public ExampleMenu(PlayerWrapper player, MenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerActionHandler("tnt", click -> { topContainer().itemMap().remove(click.slot()); title("Hello, {viewer}"); build(); player().sendMessage("It simply works :)"); return CallResult.DENY_GRABBING; }); set(configuration.businessItems().get("test")); set(CirrusItem.animated(RGBColorChangeAnimation.fat("test", Color.green, Color.red))); set(CirrusItem .animated(RGBColorChangeAnimation.fat("test", Color.green, Color.red)) .slot(1, 2, 3) .glow() ); } } ================================================ FILE: cirrus-spigot-example/src/main/java/dev/simplix/cirrus/spigot/example/menus/ExampleMultiPageMenu.java ================================================ package dev.simplix.cirrus.spigot.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.menus.MultiPageMenu; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.api.providers.MappingProvider; import dev.simplix.protocolize.data.ItemType; import java.util.Collections; import java.util.Locale; public class ExampleMultiPageMenu extends MultiPageMenu { private final MappingProvider mappingProvider = Protocolize.mappingProvider(); public ExampleMultiPageMenu( PlayerWrapper player, MultiPageMenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerMyActionHandlers(); addItems(); } private void registerMyActionHandlers() { registerActionHandler("test", click -> { player().sendMessage("This is " + click.clickedItem().type().name()); return CallResult.DENY_GRABBING; }); } private void addItems() { for (ItemType type : ItemType.values()) { if (this.mappingProvider.mapping(type, player().protocolVersion()) != null) { add(wrapItemStack(new ItemStack(type)), "test", Collections.emptyList()); } } } } ================================================ FILE: cirrus-spigot-example/src/main/resources/plugin.yml ================================================ name: CirrusExample author: Exceptionflug version: 1.0 main: dev.simplix.cirrus.spigot.example.CirrusExamplePlugin api-version: 1.17 commands: test: description: Opens the test gui ================================================ FILE: cirrus-spigot-modern/pom.xml ================================================ 4.0.0 dev.simplix.cirrus cirrus 2.0.0 cirrus-spigot-modern ${cirrus.version} org.spigotmc spigot-api 1.19-R0.1-SNAPSHOT provided dev.simplix.cirrus cirrus-common ${cirrus.version} provided ================================================ FILE: cirrus-spigot-modern/src/main/java/dev/simplix/cirrus/spigot/modern/ModernInventoryView.java ================================================ package dev.simplix.cirrus.spigot.modern; import dev.simplix.cirrus.common.menu.Menu; import lombok.NonNull; import org.bukkit.entity.HumanEntity; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; public final class ModernInventoryView extends InventoryView { private final Menu menu; private final Inventory top; private final Inventory bottom; public ModernInventoryView( @NonNull Menu menu, @NonNull Inventory top, @NonNull Inventory bottom) { this.menu = menu; this.top = top; this.bottom = bottom; } @Override public Inventory getTopInventory() { return top; } @Override public Inventory getBottomInventory() { return bottom; } @Override public HumanEntity getPlayer() { return menu.player().handle(); } @Override public InventoryType getType() { return top.getType(); } @Override public String getTitle() { return menu.title(); } } ================================================ FILE: cirrus-velocity/pom.xml ================================================ 4.0.0 org.apache.maven.plugins maven-compiler-plugin maven-shade-plugin 3.2.4 package shade dev.simplix.cirrus cirrus 2.0.0 cirrus-velocity ${cirrus.version} 3.0.0 cirrus-common dev.simplix.cirrus compile ${cirrus.version} com.velocitypowered velocity-api ${velocity.version} provided ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/CirrusVelocity.java ================================================ package dev.simplix.cirrus.velocity; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.effect.MenuAnimator; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.velocity.converters.ItemModelConverter; import dev.simplix.cirrus.velocity.converters.ItemStackConverter; import dev.simplix.cirrus.velocity.converters.PlayerConverter; import dev.simplix.cirrus.velocity.converters.PlayerUniqueIdConverter; import dev.simplix.cirrus.velocity.listener.QuitListener; import dev.simplix.cirrus.velocity.protocolize.ProtocolizeMenuBuilder; import dev.simplix.protocolize.api.item.ItemStack; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * Date: 18.09.2021 * * @author Exceptionflug */ public class CirrusVelocity { private static ProxyServer proxyServer; public static void init(ProxyServer proxyServer, Object plugin) { if (CirrusVelocity.proxyServer != null) { return; } CirrusVelocity.proxyServer = proxyServer; Cirrus.registerService(MenuBuilder.class, new ProtocolizeMenuBuilder()); proxyServer.getEventManager().register(plugin, new QuitListener()); // Players Converters.register(Player.class, PlayerWrapper.class, new PlayerConverter()); Converters.register(UUID.class, PlayerWrapper.class, new PlayerUniqueIdConverter(proxyServer)); // Items Converters.register(ItemStack.class, MenuItemWrapper.class, new ItemStackConverter()); Converters.register(CirrusItem.class, InventoryMenuItemWrapper.class, new ItemModelConverter()); proxyServer.getScheduler().buildTask(plugin, () -> { if (proxyServer.getPlayerCount() > 0 && !MenuAnimator.isEmpty()) { MenuAnimator.updateAll(); } }).repeat(50 * 2, TimeUnit.MILLISECONDS).schedule(); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/VelocityPlayerWrapper.java ================================================ package dev.simplix.cirrus.velocity; import com.velocitypowered.api.proxy.Player; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.player.ProtocolizePlayer; import java.util.UUID; import lombok.NonNull; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class VelocityPlayerWrapper implements PlayerWrapper { private final LegacyComponentSerializer legacyComponentSerializer = LegacyComponentSerializer.legacySection(); private final ProtocolizePlayer protocolizePlayer; private final Player handle; public VelocityPlayerWrapper(@NonNull Player handle) { this.handle = handle; this.protocolizePlayer = Protocolize.playerProvider().player(handle.getUniqueId()); } @Override public UUID uniqueId() { return this.handle.getUniqueId(); } @Override public String name() { return this.handle.getUsername(); } @Override public int protocolVersion() { return this.protocolizePlayer.protocolVersion(); } @Override public void sendMessage(@NonNull String msg) { this.handle.sendMessage(this.legacyComponentSerializer.deserialize(msg)); } @Override public void closeInventory() { this.protocolizePlayer.closeInventory(); } @Override public boolean hasPermission(@NonNull String permission) { return this.handle.hasPermission(permission); } @Override public T handle() { return (T) this.handle; } public ProtocolizePlayer protocolizePlayer() { return this.protocolizePlayer; } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/converters/ItemModelConverter.java ================================================ package dev.simplix.cirrus.velocity.converters; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.common.item.CirrusItem; import dev.simplix.protocolize.api.chat.ChatElement; import dev.simplix.protocolize.api.item.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.stream.Collectors; public class ItemModelConverter implements Converter { @Override public InventoryMenuItemWrapper convert(@NotNull CirrusItem model) { ItemStack itemStack = new ItemStack(model.itemType(), model.amount(), model.durability()); itemStack.nbtData(model.nbt()); itemStack.displayName(ChatElement.ofLegacyText(model.displayName())); itemStack.lore(model.lore().stream().map(ChatElement::ofLegacyText).collect(Collectors.toList())); return InventoryMenuItemWrapper.builder() .handle(Converters.convert(itemStack, MenuItemWrapper.class)) .actionArguments(model.actionArguments()) .actionHandler(model.actionHandler()) .build(); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/converters/ItemStackConverter.java ================================================ package dev.simplix.cirrus.velocity.converters; import dev.simplix.cirrus.common.business.MenuItemWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.common.item.ProtocolizeMenuItemWrapper; import dev.simplix.protocolize.api.item.ItemStack; import lombok.NonNull; public class ItemStackConverter implements Converter { @Override public MenuItemWrapper convert(@NonNull ItemStack itemStack) { return new ProtocolizeMenuItemWrapper(itemStack); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/converters/PlayerConverter.java ================================================ package dev.simplix.cirrus.velocity.converters; import com.velocitypowered.api.proxy.Player; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.velocity.VelocityPlayerWrapper; import lombok.NonNull; public final class PlayerConverter implements Converter { @Override public PlayerWrapper convert(@NonNull Player proxiedPlayer) { return new VelocityPlayerWrapper(proxiedPlayer); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/converters/PlayerUniqueIdConverter.java ================================================ package dev.simplix.cirrus.velocity.converters; import com.velocitypowered.api.proxy.ProxyServer; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converter; import dev.simplix.cirrus.velocity.VelocityPlayerWrapper; import java.util.UUID; import lombok.NonNull; public class PlayerUniqueIdConverter implements Converter { private final ProxyServer proxyServer; public PlayerUniqueIdConverter(ProxyServer proxyServer) { this.proxyServer = proxyServer; } @Override public PlayerWrapper convert(@NonNull UUID uuid) { return new VelocityPlayerWrapper(this.proxyServer.getPlayer(uuid) .orElseThrow(() -> new IllegalArgumentException("Player " + uuid + " is offline"))); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/listener/QuitListener.java ================================================ package dev.simplix.cirrus.velocity.listener; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.menu.MenuBuilder; /** * Date: 18.09.2021 * * @author Exceptionflug */ public class QuitListener { private final MenuBuilder menuBuilder = Cirrus.getService(MenuBuilder.class); @Subscribe public void onQuit(DisconnectEvent event) { this.menuBuilder.destroyMenusOfPlayer(event.getPlayer().getUniqueId()); } } ================================================ FILE: cirrus-velocity/src/main/java/dev/simplix/cirrus/velocity/protocolize/ProtocolizeMenuBuilder.java ================================================ package dev.simplix.cirrus.velocity.protocolize; import com.google.common.collect.Sets; import com.velocitypowered.api.proxy.Player; import dev.simplix.cirrus.common.business.InventoryMenuItemWrapper; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.container.Container; import dev.simplix.cirrus.common.handler.ActionHandler; import dev.simplix.cirrus.common.i18n.Replacer; import dev.simplix.cirrus.common.menu.AbstractMenu; import dev.simplix.cirrus.common.menu.Menu; import dev.simplix.cirrus.common.menu.MenuBuilder; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.cirrus.common.model.Click; import dev.simplix.cirrus.velocity.VelocityPlayerWrapper; import dev.simplix.protocolize.api.ClickType; import dev.simplix.protocolize.api.chat.ChatElement; import dev.simplix.protocolize.api.inventory.Inventory; import dev.simplix.protocolize.api.item.BaseItemStack; import dev.simplix.protocolize.api.item.ItemStack; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.Map.Entry; @Slf4j public class ProtocolizeMenuBuilder implements MenuBuilder { private final Map> buildMap = new LinkedHashMap<>(); private final Set menus = Sets.newConcurrentHashSet(); @Override public T build(@Nullable T prebuild, @NonNull Menu menu) { if (!(menu instanceof AbstractMenu)) { throw new IllegalArgumentException("This implementation can only build cirrus menus!"); } final boolean register = prebuild == null; if (prebuild instanceof Inventory) { String title = Replacer.of(menu.title()).replaceAll((Object[]) menu.replacements().get()) .replacedMessageJoined(); final Inventory inventory = (Inventory) prebuild; if (!GsonComponentSerializer.gson().serialize((Component) inventory.title().asComponent()) .equals(GsonComponentSerializer.gson().serialize(Component.text(title))) || inventory.type().getTypicalSize(menu.player().protocolVersion()) != menu .topContainer() .capacity() || inventory.type() != menu.inventoryType()) { prebuild = (T) makeInv(menu); } } else { prebuild = (T) makeInv(menu); } final Inventory inventory = (Inventory) prebuild; buildContainer(inventory, menu.topContainer()); buildContainer(inventory, menu.bottomContainer()); this.buildMap.put( menu.player().uniqueId(), new AbstractMap.SimpleEntry<>(menu, System.currentTimeMillis())); if (register) { this.menus.add(menu); } open(menu.player(), inventory); return prebuild; } private void buildContainer(@NonNull Inventory inventory, @NonNull Container container) { for (int i = container.baseSlot(); i < container.baseSlot() + container.capacity(); i++) { InventoryMenuItemWrapper item = container.itemMap().get(i); BaseItemStack currentStack = inventory.item(i); if (item == null) { if (currentStack != null) { inventory.item(i, ItemStack.NO_DATA); } } if (item != null) { if (currentStack == null) { if (item.handle() == null) { log.error("InventoryItem's ItemStackWrapper is null @ slot " + i); continue; } inventory.item(i, item.handle()); } else { if (!currentStack.equals(item.handle())) { inventory.item(i, item.handle()); } } } } } private Inventory makeInv(@NonNull Menu menu) { Inventory inventory = new Inventory(menu.inventoryType()); inventory.title(ChatElement.ofLegacyText(menu.title())); inventory.onClose(inventoryClose -> { Entry lastBuild = lastBuildOfPlayer(inventoryClose.player().uniqueId()); if (((AbstractMenu) lastBuild.getKey()).internalId() == ((AbstractMenu) menu).internalId() && (System.currentTimeMillis() - lastBuild.getValue()) <= 55) { return; } menu.handleClose((System.currentTimeMillis() - lastBuild.getValue()) <= 55); invalidate(menu); }); inventory.onClick(inventoryClick -> { if (inventoryClick.clickType() == null) { return; } if (inventoryClick.player() == null) { return; } Inventory i = inventoryClick.inventory(); if (i == null) { return; } // ProxyServer.getInstance().broadcast("Clicked inventory"); // ProxyServer.getInstance().broadcast("Clicked menu: " + menu.getClass().getSimpleName() + " @ slot " + event.getSlot()); Container container; if (inventoryClick.slot() > menu.topContainer().capacity() - 1) { container = menu.bottomContainer(); // ProxyServer.getInstance().broadcast("Clicked bottom container"); } else { container = menu.topContainer(); // ProxyServer.getInstance().broadcast("Clicked top container"); } InventoryMenuItemWrapper item = container.get(inventoryClick.slot()); ClickType type = inventoryClick.clickType(); if (item == null) { // ProxyServer.getInstance().broadcast("Clicked nothing"); if (menu.customActionHandler() != null) { try { CallResult callResult = menu .customActionHandler() .handle(new Click(type, menu, null, inventoryClick.slot())); inventoryClick.cancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (Exception ex) { inventoryClick.cancelled(true); menu.handleException(null, ex); } } return; } // ProxyServer.getInstance().broadcast("Clicked "+item.displayName()); ActionHandler actionHandler = menu.actionHandler(item.actionHandler()); if (actionHandler == null) { inventoryClick.cancelled(true); return; } try { final CallResult callResult = actionHandler.handle(new Click( type, menu, item, inventoryClick.slot())); inventoryClick.cancelled(callResult == null || callResult == CallResult.DENY_GRABBING); } catch (final Exception ex) { inventoryClick.cancelled(true); menu.handleException(actionHandler, ex); } }); return inventory; } @Override public void open( PlayerWrapper playerWrapper, T inventoryImpl) { if (playerWrapper instanceof VelocityPlayerWrapper) { ((VelocityPlayerWrapper) playerWrapper).protocolizePlayer().openInventory((Inventory) inventoryImpl); } } @Override @Nullable public Menu menuByHandle(Object handle) { if (handle == null) { return null; } for (final Menu menu : this.menus) { if (menu.equals(handle)) { return menu; } } return null; } @Override public void destroyMenusOfPlayer(@NonNull UUID uniqueId) { this.menus.removeIf( wrapper -> ((Player) wrapper.player().handle()).getUniqueId().equals(uniqueId)); this.buildMap.remove(uniqueId); } @Override public Entry lastBuildOfPlayer(@NonNull UUID uniqueId) { return this.buildMap.get(uniqueId); } @Override public void invalidate(@NonNull Menu menu) { this.menus.remove(menu); } } ================================================ FILE: cirrus-velocity-example/.gitignore ================================================ # User-specific stuff .idea/ *.iml *.ipr *.iws # IntelliJ out/ # Compiled class file *.class # Log file *.log # BlueJ files *.ctxt # Package Files # *.jar *.war *.nar *.ear *.zip *.tar.gz *.rar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # Windows thumbnail cache files Thumbs.db Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties .mvn/wrapper/maven-wrapper.jar .flattened-pom.xml # Common working directory run/ ================================================ FILE: cirrus-velocity-example/pom.xml ================================================ 4.0.0 dev.simplix.cirrus cirrus 2.0.0 cirrus-velocity-example ${cirrus.version} cirrus-common dev.simplix.cirrus compile ${cirrus.version} cirrus-velocity dev.simplix.cirrus compile ${cirrus.version} com.velocitypowered velocity-api 3.0.0 provided ${project.name}-${project.version} src/main/resources true org.apache.maven.plugins maven-shade-plugin 3.0.0 package shade org.apache.maven.plugins maven-compiler-plugin 8 8 ================================================ FILE: cirrus-velocity-example/src/main/java/dev/simplix/cirrus/velocity/example/CirrusExamplePlugin.java ================================================ package dev.simplix.cirrus.velocity.example; import com.google.inject.Inject; import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.ProxyServer; import dev.simplix.cirrus.velocity.CirrusVelocity; import dev.simplix.cirrus.velocity.example.commands.TestCommand; @Plugin( id = "cirrusexample", name = "CirrusExample", version = "1.0", authors = "Xefreh" ) public class CirrusExamplePlugin { private final ProxyServer proxyServer; private final CommandManager commandManager; @Inject public CirrusExamplePlugin(ProxyServer proxyServer, CommandManager commandManager) { this.proxyServer = proxyServer; this.commandManager = commandManager; } @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) { CirrusVelocity.init(proxyServer, this); commandManager.register("test", new TestCommand()); } } ================================================ FILE: cirrus-velocity-example/src/main/java/dev/simplix/cirrus/velocity/example/commands/TestCommand.java ================================================ package dev.simplix.cirrus.velocity.example.commands; import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.proxy.Player; import dev.simplix.cirrus.common.Cirrus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.converter.Converters; import dev.simplix.cirrus.velocity.example.menus.ExampleMenu; public class TestCommand implements SimpleCommand { @Override public void execute(Invocation invocation) { if (invocation.source() instanceof Player) { Player player = (Player) invocation.source(); new ExampleMenu(Converters.convert(player, PlayerWrapper.class), Cirrus.configurationFactory().loadFile("plugins/Cirrus/example.json")).open(); } } } ================================================ FILE: cirrus-velocity-example/src/main/java/dev/simplix/cirrus/velocity/example/menus/ExampleMenu.java ================================================ package dev.simplix.cirrus.velocity.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MenuConfiguration; import dev.simplix.cirrus.common.menus.SimpleMenu; import dev.simplix.cirrus.common.model.CallResult; import java.util.Locale; public class ExampleMenu extends SimpleMenu { public ExampleMenu(PlayerWrapper player, MenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerActionHandler("tnt", click -> { topContainer().itemMap().remove(click.slot()); title("Hello, {viewer}"); build(); player().sendMessage("It simply works :)"); return CallResult.DENY_GRABBING; }); } } ================================================ FILE: cirrus-velocity-example/src/main/java/dev/simplix/cirrus/velocity/example/menus/ExampleMultiPageMenu.java ================================================ package dev.simplix.cirrus.velocity.example.menus; import dev.simplix.cirrus.common.business.PlayerWrapper; import dev.simplix.cirrus.common.configuration.MultiPageMenuConfiguration; import dev.simplix.cirrus.common.menus.MultiPageMenu; import dev.simplix.cirrus.common.model.CallResult; import dev.simplix.protocolize.api.Protocolize; import dev.simplix.protocolize.api.item.ItemStack; import dev.simplix.protocolize.api.providers.MappingProvider; import dev.simplix.protocolize.data.ItemType; import java.util.Collections; import java.util.Locale; public class ExampleMultiPageMenu extends MultiPageMenu { private final MappingProvider mappingProvider = Protocolize.mappingProvider(); public ExampleMultiPageMenu( PlayerWrapper player, MultiPageMenuConfiguration configuration) { super(player, configuration, Locale.ENGLISH); registerMyActionHandlers(); addItems(); } private void registerMyActionHandlers() { registerActionHandler("test", click -> { player().sendMessage("This is " + click.clickedItem().type().name()); return CallResult.DENY_GRABBING; }); } private void addItems() { for (ItemType type : ItemType.values()) { if (this.mappingProvider.mapping(type, player().protocolVersion()) != null) { add(wrapItemStack(new ItemStack(type)), "test", Collections.emptyList()); } } } } ================================================ FILE: pom.xml ================================================ cirrus dev.simplix.cirrus 4.0.0 pom 2.0.0 8 8 1.8 2.0.0 UTF-8 protocolize-api dev.simplix provided 2.4.1 org.jetbrains annotations 23.0.0 provided lombok org.projectlombok provided 1.18.22 gson com.google.code.gson provided 2.8.9 bungeecord-chat net.md-5 provided 1.21-R0.1-SNAPSHOT junit-jupiter org.junit.jupiter test 5.7.0-M1 com.mojang authlib 1.5.21 provided cirrus-common cirrus-bungeecord cirrus-velocity cirrus-spigot cirrus-spigot-modern cirrus-bungeecord-example cirrus-spigot-example cirrus-velocity-example jitpack.io https://jitpack.io simplixsoft-public https://repo.simplix.dev/repository/simplixsoft-public/ exceptionflug https://mvn.exceptionflug.de/repository/exceptionflug-public/ velocity https://repo.velocitypowered.com/snapshots/ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ minecraft-repo https://libraries.minecraft.net/ simplixsoft-public https://repo.simplix.dev/repository/simplixsoft-public/ simplixsoft-public https://repo.simplix.dev/repository/simplixsoft-public/