diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b4885be --- /dev/null +++ b/.editorconfig @@ -0,0 +1,272 @@ +root = true + +[*] +charset = utf-8 + +[*.java] +indent_style = tab +ij_continuation_indent_size = 4 +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 = false +ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_deconstruction_list_components = true +ij_java_align_multiline_extends_list = false +ij_java_align_multiline_for = true +ij_java_align_multiline_method_parentheses = false +ij_java_align_multiline_parameters = true +ij_java_align_multiline_parameters_in_calls = false +ij_java_align_multiline_parenthesized_expression = false +ij_java_align_multiline_records = true +ij_java_align_multiline_resources = true +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = false +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_align_types_in_multi_catch = true +ij_java_annotation_parameter_wrap = off +ij_java_array_initializer_new_line_after_left_brace = false +ij_java_array_initializer_right_brace_on_new_line = false +ij_java_array_initializer_wrap = off +ij_java_assert_statement_colon_on_next_line = false +ij_java_assert_statement_wrap = off +ij_java_assignment_wrap = off +ij_java_binary_operation_sign_on_next_line = false +ij_java_binary_operation_wrap = off +ij_java_blank_lines_after_anonymous_class_header = 0 +ij_java_blank_lines_after_class_header = 0 +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_after_package = 1 +ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_around_field = 0 +ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_field_with_annotations = 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 = next_line +ij_java_block_comment_add_space = false +ij_java_block_comment_at_first_column = true +ij_java_builder_methods = +ij_java_call_parameters_new_line_after_left_paren = false +ij_java_call_parameters_right_paren_on_new_line = false +ij_java_call_parameters_wrap = off +ij_java_case_statement_on_separate_line = true +ij_java_catch_on_new_line = true +ij_java_class_annotation_wrap = split_into_lines +ij_java_class_brace_style = next_line +ij_java_class_count_to_use_import_on_demand = 5 +ij_java_class_names_in_javadoc = 1 +ij_java_deconstruction_list_wrap = normal +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_not_wrap_after_single_annotation_in_parameter = false +ij_java_do_while_brace_force = never +ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_param_comments = false +ij_java_doc_add_blank_line_after_return = false +ij_java_doc_add_p_tag_on_empty_lines = true +ij_java_doc_align_exception_comments = true +ij_java_doc_align_param_comments = true +ij_java_doc_do_not_wrap_if_one_line = false +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = true +ij_java_enum_constants_wrap = off +ij_java_enum_field_annotation_wrap = off +ij_java_extends_keyword_wrap = off +ij_java_extends_list_wrap = off +ij_java_field_annotation_wrap = split_into_lines +ij_java_field_name_prefix = +ij_java_field_name_suffix = +ij_java_finally_on_new_line = true +ij_java_for_brace_force = never +ij_java_for_statement_new_line_after_left_paren = false +ij_java_for_statement_right_paren_on_new_line = false +ij_java_for_statement_wrap = off +ij_java_generate_final_locals = false +ij_java_generate_final_parameters = false +ij_java_generate_use_type_annotation_before_type = true +ij_java_if_brace_force = never +ij_java_imports_layout = *,|,javax.**,java.**,|,$* +ij_java_indent_case_from_switch = true +ij_java_insert_inner_class_imports = false +ij_java_insert_override_annotation = true +ij_java_keep_blank_lines_before_right_brace = 2 +ij_java_keep_blank_lines_between_package_declaration_and_header = 2 +ij_java_keep_blank_lines_in_code = 2 +ij_java_keep_blank_lines_in_declarations = 2 +ij_java_keep_builder_methods_indents = false +ij_java_keep_control_statement_in_one_line = true +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_add_space_on_reformat = false +ij_java_line_comment_at_first_column = true +ij_java_local_variable_name_prefix = +ij_java_local_variable_name_suffix = +ij_java_method_annotation_wrap = split_into_lines +ij_java_method_brace_style = next_line +ij_java_method_call_chain_wrap = off +ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_right_paren_on_new_line = false +ij_java_method_parameters_wrap = off +ij_java_modifier_list_wrap = false +ij_java_multi_catch_types_wrap = normal +ij_java_names_count_to_use_import_on_demand = 3 +ij_java_new_line_after_lparen_in_annotation = false +ij_java_new_line_after_lparen_in_deconstruction_pattern = true +ij_java_new_line_after_lparen_in_record_header = false +ij_java_new_line_when_body_is_presented = false +ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_parameter_annotation_wrap = off +ij_java_parameter_name_prefix = +ij_java_parameter_name_suffix = +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_annotations = +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = off +ij_java_rparen_on_new_line_in_annotation = false +ij_java_rparen_on_new_line_in_deconstruction_pattern = true +ij_java_rparen_on_new_line_in_record_header = false +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_deconstruction_list = 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_annotation_eq = 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_inside_block_braces_when_body_is_present = 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_deconstruction_list = false +ij_java_spaces_within_for_parentheses = false +ij_java_spaces_within_if_parentheses = false +ij_java_spaces_within_method_call_parentheses = false +ij_java_spaces_within_method_parentheses = false +ij_java_spaces_within_parentheses = false +ij_java_spaces_within_record_header = false +ij_java_spaces_within_switch_parentheses = false +ij_java_spaces_within_synchronized_parentheses = false +ij_java_spaces_within_try_parentheses = false +ij_java_spaces_within_while_parentheses = false +ij_java_special_else_if_treatment = true +ij_java_static_field_name_prefix = +ij_java_static_field_name_suffix = +ij_java_subclass_name_prefix = +ij_java_subclass_name_suffix = Impl +ij_java_switch_expressions_wrap = normal +ij_java_ternary_operation_signs_on_next_line = false +ij_java_ternary_operation_wrap = off +ij_java_test_name_prefix = +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = off +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 = false +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = false +ij_java_wrap_semicolon_after_call_chain = false \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index bec67ba..0ae3bf9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,4 @@ org.gradle.daemon=false # Mod Properties maven_group = squeek.appleskin archives_base_name = appleskin-forge -mod_version = 2.5.1 +mod_version = 2.7.0 diff --git a/java/squeek/appleskin/AppleSkin.java b/java/squeek/appleskin/AppleSkin.java index ef4a4f2..143d9db 100644 --- a/java/squeek/appleskin/AppleSkin.java +++ b/java/squeek/appleskin/AppleSkin.java @@ -33,6 +33,8 @@ public AppleSkin() net.minecraftforge.fml.config.ModConfig.Type.CLIENT, ModConfig.SPEC ); + FMLJavaModLoadingContext.get().getModEventBus().addListener(ModConfig::onConfigReloading); + FMLJavaModLoadingContext.get().getModEventBus().addListener(ModConfig::onConfigLoading); ModConfig.init(FMLPaths.CONFIGDIR.get().resolve(ModInfo.MODID + "-client.toml")); // Register ourselves for server and other game events we are interested in diff --git a/java/squeek/appleskin/ModConfig.java b/java/squeek/appleskin/ModConfig.java index c9a2fc7..0d1faf0 100644 --- a/java/squeek/appleskin/ModConfig.java +++ b/java/squeek/appleskin/ModConfig.java @@ -3,8 +3,11 @@ import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.electronwill.nightconfig.core.io.WritingMode; import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.event.config.ModConfigEvent; import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; public class ModConfig { @@ -47,6 +50,12 @@ public static void init(Path file) private static final String SHOW_SATURATION_OVERLAY_COMMENT = "If true, shows your current saturation level overlayed on the hunger bar"; + public static final ForgeConfigSpec.BooleanValue SHOW_SATURATION_TEXT_OVERLAY; + public static boolean SHOW_SATURATION_TEXT_OVERLAY_DEFAULT = true; + private static final String SHOW_SATURATION_TEXT_OVERLAY_NAME = "showSaturationTextHudOverlay"; + private static final String SHOW_SATURATION_TEXT_OVERLAY_COMMENT = + "If true, shows the numerical value of your current saturation level"; + public static final ForgeConfigSpec.BooleanValue SHOW_FOOD_VALUES_OVERLAY; public static boolean SHOW_FOOD_VALUES_OVERLAY_DEFAULT = true; private static final String SHOW_FOOD_VALUES_OVERLAY_NAME = "showFoodValuesHudOverlay"; @@ -89,6 +98,21 @@ public static void init(Path file) private static final String MAX_HUD_OVERLAY_FLASH_ALPHA_COMMENT = "Alpha value of the flashing icons at their most visible point (1.0 = fully opaque, 0.0 = fully transparent)"; + public static final ForgeConfigSpec.ConfigValue> SATURATION_HUD_OVERLAY_COLORS; + public static List SATURATION_HUD_OVERLAY_COLORS_DEFAULT = Arrays.asList( + "#FFD500", + "#FF0000", + "#0000FF", + "#E600FF", + "#FF8B3D", + "#00FFFF", + "#45018F", + "#00FF00" + ); + private static final String SATURATION_HUD_OVERLAY_COLORS_NAME = "saturationHudOverlayColors"; + private static final String SATURATION_HUD_OVERLAY_COLORS_COMMENT = + "The colors to use for the saturation HUD overlay. The colors are in ARGB hex format."; + static { BUILDER.push(CATEGORY_CLIENT); @@ -101,6 +125,9 @@ public static void init(Path file) SHOW_SATURATION_OVERLAY = BUILDER .comment(SHOW_SATURATION_OVERLAY_COMMENT) .define(SHOW_SATURATION_OVERLAY_NAME, SHOW_SATURATION_OVERLAY_DEFAULT); + SHOW_SATURATION_TEXT_OVERLAY = BUILDER + .comment(SHOW_SATURATION_TEXT_OVERLAY_COMMENT) + .define(SHOW_SATURATION_TEXT_OVERLAY_NAME, SHOW_SATURATION_TEXT_OVERLAY_DEFAULT); SHOW_FOOD_VALUES_OVERLAY = BUILDER .comment(SHOW_FOOD_VALUES_OVERLAY_COMMENT) .define(SHOW_FOOD_VALUES_OVERLAY_NAME, SHOW_FOOD_VALUES_OVERLAY_DEFAULT); @@ -122,8 +149,58 @@ public static void init(Path file) MAX_HUD_OVERLAY_FLASH_ALPHA = BUILDER .comment(MAX_HUD_OVERLAY_FLASH_ALPHA_COMMENT) .defineInRange(MAX_HUD_OVERLAY_FLASH_ALPHA_NAME, MAX_HUD_OVERLAY_FLASH_ALPHA_DEFAULT, 0D, 1D); + SATURATION_HUD_OVERLAY_COLORS = BUILDER + .comment(SATURATION_HUD_OVERLAY_COLORS_COMMENT) + .defineList(SATURATION_HUD_OVERLAY_COLORS_NAME, SATURATION_HUD_OVERLAY_COLORS_DEFAULT, o -> o instanceof String); BUILDER.pop(); } + public static int[] SATURATION_HUD_OVERLAY_COLORS_CACHE = SATURATION_HUD_OVERLAY_COLORS_DEFAULT.stream().mapToInt(color -> { + try + { + return Integer.decode(color); + } + catch (NumberFormatException e) + { + return 0xFFD500; // fallback (yellow) + } + }).toArray(); + + public static void onConfigReloading(ModConfigEvent.Reloading event) + { + if (event.getConfig().getSpec() == SPEC) + { + SATURATION_HUD_OVERLAY_COLORS_CACHE = SATURATION_HUD_OVERLAY_COLORS.get().stream().mapToInt(color -> { + try + { + return Integer.decode(color); + } + catch (NumberFormatException e) + { + AppleSkin.Log.warn("Invalid color value in config: {}", color); + return 0xFFD500; // fallback (yellow) + } + }).toArray(); + } + } + + public static void onConfigLoading(ModConfigEvent.Loading event) + { + if (event.getConfig().getSpec() == SPEC) + { + SATURATION_HUD_OVERLAY_COLORS_CACHE = SATURATION_HUD_OVERLAY_COLORS.get().stream().mapToInt(color -> { + try + { + return Integer.decode(color); + } + catch (NumberFormatException e) + { + AppleSkin.Log.warn("Invalid color value in config: {}", color); + return 0xFFD500; // fallback (yellow) + } + }).toArray(); + } + } + public static final ForgeConfigSpec SPEC = BUILDER.build(); -} \ No newline at end of file +} diff --git a/java/squeek/appleskin/client/HUDOverlayHandler.java b/java/squeek/appleskin/client/HUDOverlayHandler.java index 99385df..a454d0c 100644 --- a/java/squeek/appleskin/client/HUDOverlayHandler.java +++ b/java/squeek/appleskin/client/HUDOverlayHandler.java @@ -95,8 +95,7 @@ public static void renderExhaustion(ForgeGui gui, GuiGraphics guiGraphics, float { foodIconsOffset = gui.rightHeight; - if (!ModConfig.SHOW_FOOD_EXHAUSTION_UNDERLAY.get()) - return; + if (!ModConfig.SHOW_FOOD_EXHAUSTION_UNDERLAY.get()) return; Minecraft mc = Minecraft.getInstance(); Player player = mc.player; @@ -109,20 +108,17 @@ public static void renderExhaustion(ForgeGui gui, GuiGraphics guiGraphics, float // Notify everyone that we should render exhaustion hud overlay HUDOverlayEvent.Exhaustion renderEvent = new HUDOverlayEvent.Exhaustion(exhaustion, right, top, guiGraphics); MinecraftForge.EVENT_BUS.post(renderEvent); - if (!renderEvent.isCanceled()) - drawExhaustionOverlay(renderEvent, mc, 1f); + if (!renderEvent.isCanceled()) drawExhaustionOverlay(renderEvent, mc, 1f); } enum RenderOverlayType { - HEALTH, - FOOD, + HEALTH, FOOD, } public static void renderFoodOrHealthOverlay(ForgeGui gui, GuiGraphics guiGraphics, float partialTicks, int screenWidth, int screenHeight, RenderOverlayType type) { - if (!shouldRenderAnyOverlays()) - return; + if (!shouldRenderAnyOverlays()) return; Minecraft mc = Minecraft.getInstance(); Player player = mc.player; @@ -133,10 +129,8 @@ public static void renderFoodOrHealthOverlay(ForgeGui gui, GuiGraphics guiGraphi int left = mc.getWindow().getGuiScaledWidth() / 2 - 91; // left of health bar int right = mc.getWindow().getGuiScaledWidth() / 2 + 91; // right of food bar - if (type == RenderOverlayType.HEALTH) - generateHealthBarOffsets(top, left, right, mc.gui.getGuiTicks(), player); - if (type == RenderOverlayType.FOOD) - generateHungerBarOffsets(top, left, right, mc.gui.getGuiTicks(), player); + if (type == RenderOverlayType.HEALTH) generateHealthBarOffsets(top, left, right, mc.gui.getGuiTicks(), player); + if (type == RenderOverlayType.FOOD) generateHungerBarOffsets(top, left, right, mc.gui.getGuiTicks(), player); HUDOverlayEvent.Saturation saturationRenderEvent = null; if (type == RenderOverlayType.FOOD) @@ -144,16 +138,13 @@ public static void renderFoodOrHealthOverlay(ForgeGui gui, GuiGraphics guiGraphi saturationRenderEvent = new HUDOverlayEvent.Saturation(stats.getSaturationLevel(), right, top, guiGraphics); // cancel render overlay event when configuration disabled. - if (!ModConfig.SHOW_SATURATION_OVERLAY.get()) - saturationRenderEvent.setCanceled(true); + if (!ModConfig.SHOW_SATURATION_OVERLAY.get()) saturationRenderEvent.setCanceled(true); // notify everyone that we should render saturation hud overlay - if (!saturationRenderEvent.isCanceled()) - MinecraftForge.EVENT_BUS.post(saturationRenderEvent); + if (!saturationRenderEvent.isCanceled()) MinecraftForge.EVENT_BUS.post(saturationRenderEvent); // the render saturation event maybe cancelled by other mods - if (!saturationRenderEvent.isCanceled()) - drawSaturationOverlay(saturationRenderEvent, mc, 0, 1f); + if (!saturationRenderEvent.isCanceled()) drawSaturationOverlay(saturationRenderEvent, mc, 0, 1f); } // try to get the item stack in the player hand @@ -176,11 +167,9 @@ public static void renderFoodOrHealthOverlay(ForgeGui gui, GuiGraphics guiGraphi if (type == RenderOverlayType.HEALTH) { // Offsets size is set to zero intentionally to disable rendering when health is infinite. - if (healthBarOffsets.size() == 0) - return; + if (healthBarOffsets.isEmpty()) return; - if (!shouldShowEstimatedHealth(heldItem, modifiedFoodValues)) - return; + if (!shouldShowEstimatedHealth(heldItem, modifiedFoodValues)) return; float foodHealthIncrement = FoodHelper.getEstimatedHealthIncrement(heldItem, modifiedFoodValues, player); float currentHealth = player.getHealth(); @@ -192,22 +181,19 @@ public static void renderFoodOrHealthOverlay(ForgeGui gui, GuiGraphics guiGraphi healthRenderEvent = new HUDOverlayEvent.HealthRestored(modifiedHealth, heldItem, modifiedFoodValues, left, top, guiGraphics); // notify everyone that we should render estimated health hud - if (healthRenderEvent != null) - MinecraftForge.EVENT_BUS.post(healthRenderEvent); + if (healthRenderEvent != null) MinecraftForge.EVENT_BUS.post(healthRenderEvent); if (healthRenderEvent != null && !healthRenderEvent.isCanceled()) drawHealthOverlay(healthRenderEvent, mc, flashAlpha); } else if (type == RenderOverlayType.FOOD) { - if (!ModConfig.SHOW_FOOD_VALUES_OVERLAY.get()) - return; + if (!ModConfig.SHOW_FOOD_VALUES_OVERLAY.get()) return; // notify everyone that we should render hunger hud overlay HUDOverlayEvent.HungerRestored renderRenderEvent = new HUDOverlayEvent.HungerRestored(stats.getFoodLevel(), heldItem, modifiedFoodValues, right, top, guiGraphics); MinecraftForge.EVENT_BUS.post(renderRenderEvent); - if (renderRenderEvent.isCanceled()) - return; + if (renderRenderEvent.isCanceled()) return; // calculate the final hunger and saturation int foodHunger = modifiedFoodValues.hunger; @@ -217,7 +203,6 @@ else if (type == RenderOverlayType.FOOD) drawHungerOverlay(renderRenderEvent, mc, foodHunger, flashAlpha, FoodHelper.isRotten(heldItem, player)); // The render saturation overlay event maybe cancelled by other mods - assert saturationRenderEvent != null; if (!saturationRenderEvent.isCanceled()) { int newFoodValue = stats.getFoodLevel() + foodHunger; @@ -231,56 +216,96 @@ else if (type == RenderOverlayType.FOOD) public static void drawSaturationOverlay(float saturationGained, float saturationLevel, Minecraft mc, GuiGraphics guiGraphics, int right, int top, float alpha) { - if (saturationLevel + saturationGained < 0) - return; - - enableAlpha(alpha); + float totalSaturation = saturationLevel + saturationGained; + if (totalSaturation <= 0) return; - float modifiedSaturation = Math.max(0, Math.min(saturationLevel + saturationGained, 20)); + int iconSize = 9; + int maxBars = 10; + float saturationPerLayer = 20f; + float saturationPerBar = saturationPerLayer / maxBars; - int startSaturationBar = 0; - int endSaturationBar = (int) Math.ceil(modifiedSaturation / 2.0F); + int[] colors = ModConfig.SATURATION_HUD_OVERLAY_COLORS_CACHE; - // when require rendering the gained saturation, start should relocation to current saturation tail. - if (saturationGained != 0) - startSaturationBar = (int) Math.max(saturationLevel / 2.0F, 0); + int fullLayers = (int) (totalSaturation / saturationPerLayer); + float remainder = totalSaturation % saturationPerLayer; - int iconSize = 9; + // FIX: Only draw the top-most full layer. + // Drawing layers 0 through fullLayers-2 is a waste of GPU cycles. + if (fullLayers > 0) + { + // If there is a remainder, the "full" layer below it is at index fullLayers - 1 + // If there is NO remainder, the top-most full layer is also fullLayers - 1 + int topFullLayerIndex = fullLayers - 1; + + int color = ((int) (alpha * 255) << 24) | colors[topFullLayerIndex % colors.length]; + float r = ((color >> 16) & 255) / 255f; + float g = ((color >> 8) & 255) / 255f; + float b = (color & 255) / 255f; + float a = ((color >> 24) & 255) / 255f; + guiGraphics.setColor(r, g, b, a); + + // Draw only the 10 bars for this specific layer + for (int i = 0; i < maxBars; i++) + { + IntPoint offset = foodBarOffsets.get(i); + if (offset != null) { + guiGraphics.blit(TextureHelper.MOD_ICONS, right + offset.x, top + offset.y, 7 * iconSize, 0, iconSize, iconSize); + } + } + } - for (int i = startSaturationBar; i < endSaturationBar; ++i) + // Draw the partial layer (the very top) + if (remainder > 0) { - // gets the offset that needs to be render of icon - IntPoint offset = foodBarOffsets.get(i); - if (offset == null) - continue; + int color = ((int) (alpha * 255) << 24) | colors[fullLayers % colors.length]; + float r = ((color >> 16) & 255) / 255f; + float g = ((color >> 8) & 255) / 255f; + float b = (color & 255) / 255f; + float a = ((color >> 24) & 255) / 255f; + guiGraphics.setColor(r, g, b, a); - int x = right + offset.x; - int y = top + offset.y; + int fullBars = (int) (remainder / saturationPerBar); + float lastBarFraction = remainder % saturationPerBar; - int v = 0; - int u = 0; + for (int i = 0; i < fullBars; i++) + { + IntPoint offset = foodBarOffsets.get(i); + if (offset != null) { + guiGraphics.blit(TextureHelper.MOD_ICONS, right + offset.x, top + offset.y, 7 * iconSize, 0, iconSize, iconSize); + } + } - float effectiveSaturationOfBar = (modifiedSaturation / 2.0F) - i; + if (lastBarFraction > 0 && fullBars < maxBars) + { + IntPoint offset = foodBarOffsets.get(fullBars); + if (offset != null) + { + int u = lastBarFraction >= 1.5f ? 6 * iconSize : lastBarFraction >= 1f ? 5 * iconSize : lastBarFraction > .5f ? 4 * iconSize : 0; + guiGraphics.blit(TextureHelper.MOD_ICONS, right + offset.x, top + offset.y, u, 0, iconSize, iconSize); + } + } + } - if (effectiveSaturationOfBar >= 1) - u = 3 * iconSize; - else if (effectiveSaturationOfBar > .5) - u = 2 * iconSize; - else if (effectiveSaturationOfBar > .25) - u = 1 * iconSize; + guiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F); - guiGraphics.blit(TextureHelper.MOD_ICONS, x, y, u, v, iconSize, iconSize); + if (ModConfig.SHOW_SATURATION_TEXT_OVERLAY.get()) + { + String text; + if(totalSaturation % 20 == 0) { + text = "" + fullLayers; + } else { + text = "" + (fullLayers + 1); + } + int x = right + 2; + int y = top + 1; + int textColor = ((int) (alpha * 255) << 24) | 0xFFFFFF; + guiGraphics.drawString(mc.font, text, x, y, textColor, true); } - - // rebind default icons - RenderSystem.setShaderTexture(0, TextureHelper.MC_ICONS); - disableAlpha(alpha); } public static void drawHungerOverlay(int hungerRestored, int foodLevel, Minecraft mc, GuiGraphics guiGraphics, int right, int top, float alpha, boolean useRottenTextures) { - if (hungerRestored <= 0) - return; + if (hungerRestored <= 0) return; enableAlpha(alpha); @@ -296,8 +321,7 @@ public static void drawHungerOverlay(int hungerRestored, int foodLevel, Minecraf { // gets the offset that needs to be render of icon IntPoint offset = foodBarOffsets.get(i); - if (offset == null) - continue; + if (offset == null) continue; int x = right + offset.x; int y = top + offset.y; @@ -315,8 +339,7 @@ public static void drawHungerOverlay(int hungerRestored, int foodLevel, Minecraf } // relocation to half food - if (i * 2 + 1 == modifiedFood) - u += 1 * iconSize; + if (i * 2 + 1 == modifiedFood) u += 1 * iconSize; // very faint background RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, alpha * 0.25F); @@ -331,8 +354,7 @@ public static void drawHungerOverlay(int hungerRestored, int foodLevel, Minecraf public static void drawHealthOverlay(float health, float modifiedHealth, Minecraft mc, GuiGraphics guiGraphics, int right, int top, float alpha) { - if (modifiedHealth <= health) - return; + if (modifiedHealth <= health) return; enableAlpha(alpha); @@ -349,8 +371,7 @@ public static void drawHealthOverlay(float health, float modifiedHealth, Minecra { // gets the offset that needs to be render of icon IntPoint offset = healthBarOffsets.get(i); - if (offset == null) - continue; + if (offset == null) continue; int x = right + offset.x; int y = top + offset.y; @@ -361,18 +382,16 @@ public static void drawHealthOverlay(float health, float modifiedHealth, Minecra int ub = iconStartOffset + 1 * iconSize; // relocation to half heart - if (i * 2 + 1 == fixedModifiedHealth) - u += 1 * iconSize; + if (i * 2 + 1 == fixedModifiedHealth) u += 1 * iconSize; // relocation to special heart of hardcore - if (isHardcore) - v = 5 * iconSize; + if (isHardcore) v = 5 * iconSize; //// apply the status effects of the player //if (player.hasStatusEffect(StatusEffects.POISON)) { - // u += 4 * iconSize; + // u += 4 * iconSize; //} else if (player.hasStatusEffect(StatusEffects.WITHER)) { - // u += 8 * iconSize; + // u += 8 * iconSize; //} // very faint background @@ -419,8 +438,7 @@ public static void disableAlpha(float alpha) @SubscribeEvent public void onClientTick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.END) - return; + if (event.phase != TickEvent.Phase.END) return; unclampedFlashAlpha += alphaDir * 0.125f; if (unclampedFlashAlpha >= 1.5f) @@ -468,30 +486,24 @@ private static boolean shouldRenderAnyOverlays() private static boolean shouldShowEstimatedHealth(ItemStack hoveredStack, FoodValues modifiedFoodValues) { // then configuration cancel the render event - if (!ModConfig.SHOW_FOOD_HEALTH_HUD_OVERLAY.get()) - return false; + if (!ModConfig.SHOW_FOOD_HEALTH_HUD_OVERLAY.get()) return false; Minecraft mc = Minecraft.getInstance(); Player player = mc.player; FoodData stats = player.getFoodData(); // in the `PEACEFUL` mode, health will restore faster - if (player.level().getDifficulty() == Difficulty.PEACEFUL) - return false; + if (player.level().getDifficulty() == Difficulty.PEACEFUL) return false; // when player has any changes health amount by any case can't show estimated health // because player will confused how much of restored/damaged healths - if (stats.getFoodLevel() >= 18) - return false; + if (stats.getFoodLevel() >= 18) return false; - if (player.hasEffect(MobEffects.POISON)) - return false; + if (player.hasEffect(MobEffects.POISON)) return false; - if (player.hasEffect(MobEffects.WITHER)) - return false; + if (player.hasEffect(MobEffects.WITHER)) return false; - if (player.hasEffect(MobEffects.REGENERATION)) - return false; + if (player.hasEffect(MobEffects.REGENERATION)) return false; return true; } @@ -512,7 +524,8 @@ private static void generateHealthBarOffsets(int top, int left, int right, int t // for thousands of hearts. // Note: Infinite and > INT_MAX absorption has been seen in the wild. // This will effectively disable rendering whenever health is unexpectedly large. - if (healthBars < 0 || healthBars > 1000) { + if (healthBars < 0 || healthBars > 1000) + { healthBarOffsets.setSize(0); return; } @@ -532,8 +545,7 @@ private static void generateHealthBarOffsets(int top, int left, int right, int t } // adjust the size - if (healthBarOffsets.size() != healthBars) - healthBarOffsets.setSize(healthBars); + if (healthBarOffsets.size() != healthBars) healthBarOffsets.setSize(healthBars); // left alignment, multiple rows, reverse for (int i = healthBars - 1; i >= 0; --i) @@ -542,8 +554,7 @@ private static void generateHealthBarOffsets(int top, int left, int right, int t int x = left + i % preferHealthBars * 8; int y = top - row * healthRowHeight; // apply the animated offset - if (shouldAnimatedHealth) - y += random.nextInt(2); + if (shouldAnimatedHealth) y += random.nextInt(2); // reuse the point object to reduce memory usage IntPoint point = healthBarOffsets.get(i); @@ -575,8 +586,7 @@ private static void generateHungerBarOffsets(int top, int left, int right, int t shouldAnimatedFood = saturationLevel <= 0.0F && ticks % (foodLevel * 3 + 1) == 0; } - if (foodBarOffsets.size() != preferFoodBars) - foodBarOffsets.setSize(preferFoodBars); + if (foodBarOffsets.size() != preferFoodBars) foodBarOffsets.setSize(preferFoodBars); // right alignment, single row for (int i = 0; i < preferFoodBars; ++i) @@ -585,8 +595,7 @@ private static void generateHungerBarOffsets(int top, int left, int right, int t int y = top; // apply the animated offset - if (shouldAnimatedFood) - y += random.nextInt(3) - 1; + if (shouldAnimatedFood) y += random.nextInt(3) - 1; // reuse the point object to reduce memory usage IntPoint point = foodBarOffsets.get(i); diff --git a/resources/assets/appleskin/textures/icons.png b/resources/assets/appleskin/textures/icons.png index 5844b03..7cb2351 100644 Binary files a/resources/assets/appleskin/textures/icons.png and b/resources/assets/appleskin/textures/icons.png differ