package com.atsuishio.superbwarfare.client.tooltip; import com.atsuishio.superbwarfare.client.tooltip.component.GunImageComponent; import com.atsuishio.superbwarfare.init.ModKeyMappings; import com.atsuishio.superbwarfare.init.ModPerks; import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.perk.AmmoPerk; import com.atsuishio.superbwarfare.perk.Perk; import com.atsuishio.superbwarfare.perk.PerkHelper; import com.atsuishio.superbwarfare.tools.GunsTool; import com.atsuishio.superbwarfare.tools.ItemNBTTool; import com.atsuishio.superbwarfare.tools.TooltipTool; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; import java.text.DecimalFormat; // TODO 等nbt重置后,修改nbt位置 public class ClientGunImageTooltip implements ClientTooltipComponent { protected final int width; protected final int height; protected final ItemStack stack; public ClientGunImageTooltip(GunImageComponent tooltip) { this.width = tooltip.width; this.height = tooltip.height; this.stack = tooltip.stack; } @Override public void renderImage(@NotNull Font font, int x, int y, GuiGraphics guiGraphics) { guiGraphics.pose().pushPose(); renderDamageAndRpmTooltip(font, guiGraphics, x, y); renderLevelAndUpgradePointTooltip(font, guiGraphics, x, y + 10); int yo = 20; if (shouldRenderBypassAndHeadshotTooltip()) { renderBypassAndHeadshotTooltip(font, guiGraphics, x, y + yo); yo += 10; } if (shouldRenderEditTooltip()) { renderWeaponEditTooltip(font, guiGraphics, x, y + yo); yo += 20; } if (shouldRenderPerks()) { if (!Screen.hasShiftDown()) { renderPerksShortcut(font, guiGraphics, x, y + yo); } else { renderPerks(font, guiGraphics, x, y + yo); } } guiGraphics.pose().popPose(); } protected boolean shouldRenderBypassAndHeadshotTooltip() { return GunsTool.getGunDoubleTag(stack, "BypassesArmor", 0) > 0 || GunsTool.getGunDoubleTag(stack, "Headshot", 0) > 0; } protected boolean shouldRenderEditTooltip() { return stack.is(ModTags.Items.CAN_CUSTOM_GUN); } protected boolean shouldRenderPerks() { return PerkHelper.getPerkByType(stack, Perk.Type.AMMO) != null || PerkHelper.getPerkByType(stack, Perk.Type.DAMAGE) != null || PerkHelper.getPerkByType(stack, Perk.Type.FUNCTIONAL) != null; } /** * 渲染武器伤害和射速 */ protected void renderDamageAndRpmTooltip(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.drawString(font, getDamageComponent(), x, y, 0xFFFFFF); int xo = font.width(getDamageComponent().getVisualOrderText()); guiGraphics.drawString(font, getRpmComponent(), x + xo + 16, y, 0xFFFFFF); } /** * 获取武器伤害的文本组件 */ protected Component getDamageComponent() { double damage = GunsTool.getGunDoubleTag(stack, "Damage", 0) * TooltipTool.perkDamage(stack); return Component.translatable("des.superbwarfare.tips.damage").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(new DecimalFormat("##.#").format(damage) + (TooltipTool.heBullet(stack) ? " + " + new DecimalFormat("##.#").format(0.8 * damage * (1 + 0.1 * TooltipTool.heBulletLevel(stack))) : "")).withStyle(ChatFormatting.GREEN)); } /** * 获取武器射速的文本组件 */ protected Component getRpmComponent() { if (!stack.is(ModTags.Items.IS_AUTO_WEAPON)) { return Component.literal(""); } else { return Component.translatable("des.superbwarfare.tips.rpm").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(new DecimalFormat("##").format(GunsTool.getGunIntTag(stack, "RPM", 0) + ItemNBTTool.getDouble(stack, "customRpm", 0))) .withStyle(ChatFormatting.GREEN)); } } /** * 渲染武器等级和强化点数 */ protected void renderLevelAndUpgradePointTooltip(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.drawString(font, getLevelComponent(), x, y, 0xFFFFFF); int xo = font.width(getLevelComponent().getVisualOrderText()); guiGraphics.drawString(font, getUpgradePointComponent(), x + xo + 16, y, 0xFFFFFF); } /** * 获取武器等级文本组件 */ protected Component getLevelComponent() { int level = ItemNBTTool.getInt(stack, "Level", 0); double rate = ItemNBTTool.getDouble(stack, "Exp", 0) / (20 * Math.pow(level, 2) + 160 * level + 20); ChatFormatting formatting; if (level < 10) { formatting = ChatFormatting.WHITE; } else if (level < 20) { formatting = ChatFormatting.AQUA; } else if (level < 30) { formatting = ChatFormatting.LIGHT_PURPLE; } else if (level < 40) { formatting = ChatFormatting.GOLD; } else { formatting = ChatFormatting.RED; } return Component.translatable("des.superbwarfare.tips.level").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(level + "").withStyle(formatting).withStyle(ChatFormatting.BOLD)) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(" (" + new DecimalFormat("#0.00").format(rate * 100) + "%)").withStyle(ChatFormatting.GRAY)); } /** * 获取武器强化点数文本组件 */ protected Component getUpgradePointComponent() { int upgradePoint = Mth.floor(ItemNBTTool.getDouble(stack, "UpgradePoint", 0)); return Component.translatable("des.superbwarfare.tips.upgrade_point").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(String.valueOf(upgradePoint)).withStyle(ChatFormatting.WHITE).withStyle(ChatFormatting.BOLD)); } /** * 渲染武器穿甲比例和爆头倍率 */ protected void renderBypassAndHeadshotTooltip(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.drawString(font, getBypassComponent(), x, y, 0xFFFFFF); int xo = font.width(getBypassComponent().getVisualOrderText()); guiGraphics.drawString(font, getHeadshotComponent(), x + xo + 16, y, 0xFFFFFF); } /** * 获取武器穿甲比例文本组件 */ protected Component getBypassComponent() { double perkBypassArmorRate = 0; var perk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); if (perk instanceof AmmoPerk ammoPerk) { int level = PerkHelper.getItemPerkLevel(perk, stack); perkBypassArmorRate = ammoPerk.bypassArmorRate + (perk == ModPerks.AP_BULLET.get() ? 0.05f * (level - 1) : 0); } double bypassRate = Math.max(GunsTool.getGunDoubleTag(stack, "BypassesArmor", 0) + perkBypassArmorRate, 0); return Component.translatable("des.superbwarfare.tips.bypass").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(new DecimalFormat("##.##").format(bypassRate * 100) + "%").withStyle(ChatFormatting.GOLD)); } /** * 获取武器爆头倍率文本组件 */ protected Component getHeadshotComponent() { double headshot = GunsTool.getGunDoubleTag(stack, "Headshot", 0); return Component.translatable("des.superbwarfare.tips.headshot").withStyle(ChatFormatting.GRAY) .append(Component.literal("").withStyle(ChatFormatting.RESET)) .append(Component.literal(new DecimalFormat("##.#").format(headshot) + "x").withStyle(ChatFormatting.AQUA)); } /** * 渲染武器改装信息 */ protected void renderWeaponEditTooltip(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.drawString(font, getEditComponent(), x, y + 10, 0xFFFFFF); } /** * 获取武器改装信息文本组件 */ protected Component getEditComponent() { return Component.translatable("des.superbwarfare.tips.edit", "[" + ModKeyMappings.EDIT_MODE.getKey().getDisplayName().getString() + "]") .withStyle(ChatFormatting.LIGHT_PURPLE).withStyle(ChatFormatting.ITALIC); } /** * 渲染武器模组缩略图 */ protected void renderPerksShortcut(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.pose().pushPose(); int xOffset = -20; Perk ammoPerk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); if (ammoPerk != null && PerkHelper.getPerkItem(ammoPerk).isPresent()) { xOffset += 20; var ammoItem = PerkHelper.getPerkItem(ammoPerk).get().get(); ItemStack perkStack = ammoItem.getDefaultInstance(); CompoundTag ammoTag = PerkHelper.getPerkTag(stack, Perk.Type.AMMO); if (!ammoTag.isEmpty()) { int level = PerkHelper.getItemPerkLevel(ammoPerk, stack); perkStack.setCount(level); } guiGraphics.renderItem(perkStack, x + xOffset, y + 2); guiGraphics.renderItemDecorations(font, perkStack, x + xOffset, y + 2); } Perk funcPerk = PerkHelper.getPerkByType(stack, Perk.Type.FUNCTIONAL); if (funcPerk != null && PerkHelper.getPerkItem(funcPerk).isPresent()) { xOffset += 20; var funcItem = PerkHelper.getPerkItem(funcPerk).get().get(); ItemStack perkStack = funcItem.getDefaultInstance(); CompoundTag funcTag = PerkHelper.getPerkTag(stack, Perk.Type.FUNCTIONAL); if (!funcTag.isEmpty()) { int level = PerkHelper.getItemPerkLevel(funcPerk, stack); perkStack.setCount(level); } guiGraphics.renderItem(perkStack, x + xOffset, y + 2); guiGraphics.renderItemDecorations(font, perkStack, x + xOffset, y + 2); } Perk damagePerk = PerkHelper.getPerkByType(stack, Perk.Type.DAMAGE); if (damagePerk != null && PerkHelper.getPerkItem(damagePerk).isPresent()) { xOffset += 20; var damageItem = PerkHelper.getPerkItem(damagePerk).get().get(); ItemStack perkStack = damageItem.getDefaultInstance(); CompoundTag damageTag = PerkHelper.getPerkTag(stack, Perk.Type.DAMAGE); if (!damageTag.isEmpty()) { int level = PerkHelper.getItemPerkLevel(damagePerk, stack); perkStack.setCount(level); } guiGraphics.renderItem(perkStack, x + xOffset, y + 2); guiGraphics.renderItemDecorations(font, perkStack, x + xOffset, y + 2); } guiGraphics.pose().popPose(); } /** * 渲染武器模组详细信息 */ protected void renderPerks(Font font, GuiGraphics guiGraphics, int x, int y) { guiGraphics.pose().pushPose(); guiGraphics.drawString(font, Component.translatable("perk.superbwarfare.tips").withStyle(ChatFormatting.GOLD).withStyle(ChatFormatting.UNDERLINE), x, y + 10, 0xFFFFFF); int yOffset = -5; Perk ammoPerk = PerkHelper.getPerkByType(stack, Perk.Type.AMMO); if (ammoPerk != null && PerkHelper.getPerkItem(ammoPerk).isPresent()) { yOffset += 25; var ammoItem = PerkHelper.getPerkItem(ammoPerk).get().get(); guiGraphics.renderItem(ammoItem.getDefaultInstance(), x, y + 4 + yOffset); CompoundTag ammoTag = PerkHelper.getPerkTag(stack, Perk.Type.AMMO); if (!ammoTag.isEmpty()) { var ids = ammoTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var ammoComponent = Component.translatable("item.superbwarfare." + id).withStyle(ChatFormatting.YELLOW) .append(Component.literal(" ").withStyle(ChatFormatting.RESET)) .append(Component.literal(" Lvl. " + ammoTag.getInt("level")).withStyle(ChatFormatting.WHITE)); var ammoDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); guiGraphics.drawString(font, ammoComponent, x + 20, y + yOffset + 2, 0xFFFFFF); guiGraphics.drawString(font, ammoDesComponent, x + 20, y + yOffset + 12, 0xFFFFFF); } } } Perk funcPerk = PerkHelper.getPerkByType(stack, Perk.Type.FUNCTIONAL); if (funcPerk != null && PerkHelper.getPerkItem(funcPerk).isPresent()) { yOffset += 25; var funcItem = PerkHelper.getPerkItem(funcPerk).get().get(); guiGraphics.renderItem(funcItem.getDefaultInstance(), x, y + 4 + yOffset); CompoundTag funcTag = PerkHelper.getPerkTag(stack, Perk.Type.FUNCTIONAL); if (!funcTag.isEmpty()) { var ids = funcTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var funcComponent = Component.translatable("item.superbwarfare." + id).withStyle(ChatFormatting.GREEN) .append(Component.literal(" ").withStyle(ChatFormatting.RESET)) .append(Component.literal(" Lvl. " + funcTag.getInt("level")).withStyle(ChatFormatting.WHITE)); var funcDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); guiGraphics.drawString(font, funcComponent, x + 20, y + yOffset + 2, 0xFFFFFF); guiGraphics.drawString(font, funcDesComponent, x + 20, y + yOffset + 12, 0xFFFFFF); } } } Perk damagePerk = PerkHelper.getPerkByType(stack, Perk.Type.DAMAGE); if (damagePerk != null && PerkHelper.getPerkItem(damagePerk).isPresent()) { yOffset += 25; var damageItem = PerkHelper.getPerkItem(damagePerk).get().get(); guiGraphics.renderItem(damageItem.getDefaultInstance(), x, y + 4 + yOffset); CompoundTag damageTag = PerkHelper.getPerkTag(stack, Perk.Type.DAMAGE); if (!damageTag.isEmpty()) { var ids = damageTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var damageComponent = Component.translatable("item.superbwarfare." + id).withStyle(ChatFormatting.RED) .append(Component.literal(" ").withStyle(ChatFormatting.RESET)) .append(Component.literal(" Lvl. " + damageTag.getInt("level")).withStyle(ChatFormatting.WHITE)); var damageDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); guiGraphics.drawString(font, damageComponent, x + 20, y + yOffset + 2, 0xFFFFFF); guiGraphics.drawString(font, damageDesComponent, x + 20, y + yOffset + 12, 0xFFFFFF); } } } guiGraphics.pose().popPose(); } protected int getDefaultMaxWidth(Font font) { int width = font.width(getDamageComponent().getVisualOrderText()) + font.width(getRpmComponent().getVisualOrderText()) + 16; width = Math.max(width, font.width(getLevelComponent().getVisualOrderText()) + font.width(getUpgradePointComponent().getVisualOrderText()) + 16); if (shouldRenderBypassAndHeadshotTooltip()) { width = Math.max(width, font.width(getBypassComponent().getVisualOrderText()) + font.width(getHeadshotComponent().getVisualOrderText()) + 16); } if (shouldRenderEditTooltip()) { width = Math.max(width, font.width(getEditComponent().getVisualOrderText()) + 16); } return width + 4; } protected int getMaxPerkDesWidth(Font font) { if (!shouldRenderPerks()) return 0; int width = 0; CompoundTag ammoTag = PerkHelper.getPerkTag(stack, Perk.Type.AMMO); if (!ammoTag.isEmpty()) { var ids = ammoTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var ammoDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); width = Math.max(width, font.width(ammoDesComponent)); } } CompoundTag funcTag = PerkHelper.getPerkTag(stack, Perk.Type.FUNCTIONAL); if (!funcTag.isEmpty()) { var ids = funcTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var funcDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); width = Math.max(width, font.width(funcDesComponent)); } } CompoundTag damageTag = PerkHelper.getPerkTag(stack, Perk.Type.DAMAGE); if (!damageTag.isEmpty()) { var ids = damageTag.getString("id").split(":"); if (ids.length > 1) { String id = ids[1]; var damageDesComponent = Component.translatable("des.superbwarfare." + id).withStyle(ChatFormatting.GRAY); width = Math.max(width, font.width(damageDesComponent)); } } return width + 25; } @Override public int getHeight() { int height = Math.max(20, this.height); if (shouldRenderBypassAndHeadshotTooltip()) height += 10; if (shouldRenderEditTooltip()) height += 20; if (shouldRenderPerks()) { if (!Screen.hasShiftDown()) { height += 16; } else { height += 16; if (PerkHelper.getPerkByType(stack, Perk.Type.AMMO) != null) { height += 25; } if (PerkHelper.getPerkByType(stack, Perk.Type.FUNCTIONAL) != null) { height += 25; } if (PerkHelper.getPerkByType(stack, Perk.Type.DAMAGE) != null) { height += 25; } } } return height; } @Override public int getWidth(@NotNull Font font) { if (Screen.hasShiftDown()) { int width = getMaxPerkDesWidth(font); return width == 0 ? Math.max(this.width, getDefaultMaxWidth(font)) : Math.max(width, getDefaultMaxWidth(font)); } else { return getDefaultMaxWidth(font); } } }