Refactored tooltips handling

- dedicated class & configuration
- more generic & flexible blockstate logic
- added entity id to spawn eggs
- optional deduplication
- added a clean list
This commit is contained in:
Unknown 2018-12-18 22:25:08 +01:00 committed by unknown
parent a1ecdcef4e
commit 8cc8402db7
7 changed files with 483 additions and 334 deletions

View file

@ -4,6 +4,7 @@ import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.event.EMPReceiver;
import cr0s.warpdrive.event.ItemHandler;
import cr0s.warpdrive.event.LivingHandler;
import cr0s.warpdrive.event.TooltipHandler;
import java.lang.ref.WeakReference;
import java.util.UUID;
@ -29,6 +30,7 @@ public class CommonProxy {
private static final WeakHashMap<GameProfile, WeakReference<EntityPlayer>> fakePlayers = new WeakHashMap<>(100);
private static EntityPlayerMP getPlayer(final WorldServer world, final UUID uuidPlayer) {
assert world.getMinecraftServer() != null;
for (final EntityPlayerMP entityPlayerMP : world.getMinecraftServer().getPlayerList().getPlayers()) {
if (entityPlayerMP.getUniqueID() == uuidPlayer) {
return entityPlayerMP;

View file

@ -169,48 +169,6 @@ public class Commons {
// logger.info(message);
}
// remove redundant information in tooltips
public static void cleanupTooltip(final List<String> list) {
// skip empty tooltip
if (list.isEmpty()) {
return;
}
// remove duplicates
final HashSet<String> setClean = new HashSet<>(list.size());
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
final String original = iterator.next();
final String clean = removeFormatting(original).trim().toLowerCase();
if (setClean.contains(clean)) {
iterator.remove();
} else if (!clean.isEmpty()) {
setClean.add(clean);
}
}
// remove extra separator lines that might be resulting from the cleanup (i.e. 2 consecutive empty lines or a final empty line)
boolean wasEmpty = false;
iterator = list.iterator();
while (iterator.hasNext()) {
final String original = iterator.next();
final String clean = removeFormatting(original).trim();
// keep line with content or at least 4 spaces (for mods adding image overlays)
if ( !clean.isEmpty()
|| original.length() > 4 ) {
wasEmpty = false;
continue;
}
// only keep first empty line in a sequence
// always remove the last line when it's empty
if ( wasEmpty
|| !iterator.hasNext() ) {
iterator.remove();
}
wasEmpty = true;
}
}
// add tooltip information with text formatting and line splitting
// will ensure it fits on minimum screen width
public static void addTooltip(final List<String> list, final String tooltip) {

View file

@ -5,6 +5,7 @@ import cr0s.warpdrive.api.IBlockBase;
import cr0s.warpdrive.api.IItemBase;
import cr0s.warpdrive.client.ClientProxy;
import cr0s.warpdrive.data.EnumTier;
import cr0s.warpdrive.event.TooltipHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -13,7 +14,6 @@ import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
@ -24,7 +24,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
@ -85,15 +84,10 @@ public class ItemBlockAbstractBase extends ItemBlock implements IItemBase {
}
public ITextComponent getStatus(final World world, @Nonnull final ItemStack itemStack) {
final IBlockState blockState;
if (world != null) {// in-game
assert Minecraft.getMinecraft().player != null;
blockState = block.getStateForPlacement(world, new BlockPos(0, -1, 0),
EnumFacing.DOWN, 0.0F, 0.0F, 0.0F,
itemStack.getMetadata(), Minecraft.getMinecraft().player, EnumHand.MAIN_HAND);
} else {// search tree
blockState = block.getStateFromMeta(itemStack.getMetadata());
}
final IBlockState blockState = TooltipHandler.getStateForPlacement(block,
world, null, EnumFacing.DOWN,
0.0F, 0.0F, 0.0F, itemStack.getMetadata(),
null, EnumHand.MAIN_HAND);
final TileEntity tileEntity = block.createTileEntity(world, blockState);
if (tileEntity instanceof TileEntityAbstractBase) {

View file

@ -6,6 +6,7 @@ import cr0s.warpdrive.api.IBlockBase;
import cr0s.warpdrive.api.IItemBase;
import cr0s.warpdrive.event.ClientHandler;
import cr0s.warpdrive.event.ModelBakeEventHandler;
import cr0s.warpdrive.event.TooltipHandler;
import cr0s.warpdrive.render.*;
import javax.annotation.Nonnull;
@ -40,6 +41,7 @@ public class ClientProxy extends CommonProxy {
// event handlers
MinecraftForge.EVENT_BUS.register(new ClientHandler());
MinecraftForge.EVENT_BUS.register(new TooltipHandler());
// generic rendering
// MinecraftForge.EVENT_BUS.register(new WarpDriveKeyBindings());

View file

@ -179,17 +179,25 @@ public class WarpDriveConfig {
public static float CLIENT_LOCATION_WIDTH_RATIO = 0.0F;
public static int CLIENT_LOCATION_WIDTH_MIN = 90;
public static EnumTooltipCondition CLIENT_TOOLTIP_REGISTRY_NAME = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition CLIENT_TOOLTIP_ORE_DICTIONARY_NAME = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition CLIENT_TOOLTIP_ARMOR = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition CLIENT_TOOLTIP_BURN_TIME = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition CLIENT_TOOLTIP_DURABILITY = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition CLIENT_TOOLTIP_FLAMMABILITY = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition CLIENT_TOOLTIP_FLUID = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition CLIENT_TOOLTIP_HARDNESS = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition CLIENT_TOOLTIP_HARVESTING = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition CLIENT_TOOLTIP_OPACITY = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition CLIENT_TOOLTIP_REPAIR_WITH = EnumTooltipCondition.ON_SNEAK;
// Tooltip
public static EnumTooltipCondition TOOLTIP_ENABLE_DEDUPLICATION = EnumTooltipCondition.ALWAYS;
public static String[] TOOLTIP_CLEANUP_LIST = new String[] {
"fuel details",
"burn time",
"durability"
};
public static EnumTooltipCondition TOOLTIP_ADD_REGISTRY_NAME = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_ORE_DICTIONARY_NAME = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition TOOLTIP_ADD_ARMOR = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition TOOLTIP_ADD_BURN_TIME = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_DURABILITY = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition TOOLTIP_ADD_ENTITY_ID = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_FLAMMABILITY = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_FLUID = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition TOOLTIP_ADD_HARDNESS = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_HARVESTING = EnumTooltipCondition.ALWAYS;
public static EnumTooltipCondition TOOLTIP_ADD_OPACITY = EnumTooltipCondition.ADVANCED_TOOLTIPS;
public static EnumTooltipCondition TOOLTIP_ADD_REPAIR_WITH = EnumTooltipCondition.ON_SNEAK;
// Logging
public static boolean LOGGING_JUMP = false;
@ -730,29 +738,43 @@ public class WarpDriveConfig {
CLIENT_LOCATION_WIDTH_MIN = config.get("client", "location_width_min", CLIENT_LOCATION_WIDTH_MIN,
"Text width as a minimum 'pixel' count").getInt();
// Tooltip
final String commentTooltip = "When to show %s in tooltips. Valid values are " + EnumTooltipCondition.formatAllValues() + ".";
CLIENT_TOOLTIP_REGISTRY_NAME = EnumTooltipCondition.valueOf(config.get("client", "tooltip_registry_name", CLIENT_TOOLTIP_REGISTRY_NAME.name(),
String.format(commentTooltip, "registry name")).getString());
CLIENT_TOOLTIP_ORE_DICTIONARY_NAME = EnumTooltipCondition.valueOf(config.get("client", "tooltip_ore_dictionary_name", CLIENT_TOOLTIP_ORE_DICTIONARY_NAME.name(),
String.format(commentTooltip, "ore dictionary names")).getString());
CLIENT_TOOLTIP_ARMOR = EnumTooltipCondition.valueOf(config.get("client", "tooltip_armor_stats", CLIENT_TOOLTIP_ARMOR.name(),
String.format(commentTooltip, "armor stats")).getString());
CLIENT_TOOLTIP_BURN_TIME = EnumTooltipCondition.valueOf(config.get("client", "tooltip_burn_time", CLIENT_TOOLTIP_BURN_TIME.name(),
String.format(commentTooltip, "burn time")).getString());
CLIENT_TOOLTIP_DURABILITY = EnumTooltipCondition.valueOf(config.get("client", "tooltip_durability", CLIENT_TOOLTIP_DURABILITY.name(),
String.format(commentTooltip, "durability")).getString());
CLIENT_TOOLTIP_FLAMMABILITY = EnumTooltipCondition.valueOf(config.get("client", "tooltip_flammability", CLIENT_TOOLTIP_FLAMMABILITY.name(),
String.format(commentTooltip, "flammability")).getString());
CLIENT_TOOLTIP_FLUID = EnumTooltipCondition.valueOf(config.get("client", "tooltip_fluid_stats", CLIENT_TOOLTIP_FLUID.name(),
String.format(commentTooltip, "fluid stats")).getString());
CLIENT_TOOLTIP_HARDNESS = EnumTooltipCondition.valueOf(config.get("client", "tooltip_hardness", CLIENT_TOOLTIP_HARDNESS.name(),
String.format(commentTooltip, "hardness & explosion resistance")).getString());
CLIENT_TOOLTIP_HARVESTING = EnumTooltipCondition.valueOf(config.get("client", "tooltip_harvesting_stats", CLIENT_TOOLTIP_HARVESTING.name(),
String.format(commentTooltip, "harvesting stats")).getString());
CLIENT_TOOLTIP_OPACITY = EnumTooltipCondition.valueOf(config.get("client", "tooltip_opacity", CLIENT_TOOLTIP_OPACITY.name(),
String.format(commentTooltip, "opacity")).getString());
CLIENT_TOOLTIP_REPAIR_WITH = EnumTooltipCondition.valueOf(config.get("client", "tooltip_repair_material", CLIENT_TOOLTIP_REPAIR_WITH.name(),
String.format(commentTooltip, "repair material")).getString());
TOOLTIP_ADD_REGISTRY_NAME = EnumTooltipCondition.valueOf(config.get("tooltip", "add_registry_name", TOOLTIP_ADD_REGISTRY_NAME.name(),
String.format(commentTooltip, "registry name")).getString());
TOOLTIP_ADD_ORE_DICTIONARY_NAME = EnumTooltipCondition.valueOf(config.get("tooltip", "add_ore_dictionary_name", TOOLTIP_ADD_ORE_DICTIONARY_NAME.name(),
String.format(commentTooltip, "ore dictionary names")).getString());
TOOLTIP_ADD_ARMOR = EnumTooltipCondition.valueOf(config.get("tooltip", "add_armor_stats", TOOLTIP_ADD_ARMOR.name(),
String.format(commentTooltip, "armor stats")).getString());
TOOLTIP_ADD_BURN_TIME = EnumTooltipCondition.valueOf(config.get("tooltip", "add_burn_time", TOOLTIP_ADD_BURN_TIME.name(),
String.format(commentTooltip, "burn time")).getString());
TOOLTIP_ADD_DURABILITY = EnumTooltipCondition.valueOf(config.get("tooltip", "add_durability", TOOLTIP_ADD_DURABILITY.name(),
String.format(commentTooltip, "durability")).getString());
TOOLTIP_ADD_ENTITY_ID = EnumTooltipCondition.valueOf(config.get("tooltip", "add_entity_id", TOOLTIP_ADD_ENTITY_ID.name(),
String.format(commentTooltip, "entity id")).getString());
TOOLTIP_ADD_FLAMMABILITY = EnumTooltipCondition.valueOf(config.get("tooltip", "add_flammability", TOOLTIP_ADD_FLAMMABILITY.name(),
String.format(commentTooltip, "flammability")).getString());
TOOLTIP_ADD_FLUID = EnumTooltipCondition.valueOf(config.get("tooltip", "add_fluid_stats", TOOLTIP_ADD_FLUID.name(),
String.format(commentTooltip, "fluid stats")).getString());
TOOLTIP_ADD_HARDNESS = EnumTooltipCondition.valueOf(config.get("tooltip", "add_hardness", TOOLTIP_ADD_HARDNESS.name(),
String.format(commentTooltip, "hardness & explosion resistance")).getString());
TOOLTIP_ADD_HARVESTING = EnumTooltipCondition.valueOf(config.get("tooltip", "add_harvesting_stats", TOOLTIP_ADD_HARVESTING.name(),
String.format(commentTooltip, "harvesting stats")).getString());
TOOLTIP_ADD_OPACITY = EnumTooltipCondition.valueOf(config.get("tooltip", "add_opacity", TOOLTIP_ADD_OPACITY.name(),
String.format(commentTooltip, "opacity")).getString());
TOOLTIP_ADD_REPAIR_WITH = EnumTooltipCondition.valueOf(config.get("tooltip", "add_repair_material", TOOLTIP_ADD_REPAIR_WITH.name(),
String.format(commentTooltip, "repair material")).getString());
TOOLTIP_CLEANUP_LIST = config.get("tooltips", "cleanup_list", TOOLTIP_CLEANUP_LIST,
"List of lines to remove from tooltips before adding ours. This can be a partial match in a line. Must be lowercase without formatting.").getStringList();
for (int index = 0; index < TOOLTIP_CLEANUP_LIST.length; index++) {
final String old = TOOLTIP_CLEANUP_LIST[index];
TOOLTIP_CLEANUP_LIST[index] = Commons.removeFormatting(old).toLowerCase();
}
TOOLTIP_ENABLE_DEDUPLICATION = EnumTooltipCondition.valueOf(config.get("tooltip", "enable_deduplication", TOOLTIP_ENABLE_DEDUPLICATION.name(),
String.format("When to remove duplicate lines in tooltips. Valid values are %s.", EnumTooltipCondition.formatAllValues())).getString());
// Logging
LOGGING_JUMP = config.get("logging", "enable_jump_logs", LOGGING_JUMP, "Basic jump logs, should always be enabled").getBoolean(true);

View file

@ -1,262 +1,14 @@
package cr0s.warpdrive.event;
import cr0s.warpdrive.Commons;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.Dictionary;
import cr0s.warpdrive.config.WarpDriveConfig;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.oredict.OreDictionary;
public class ClientHandler {
private boolean isSneaking;
private boolean isCreativeMode;
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onTooltipEvent_first(final ItemTooltipEvent event) {
if (event.getEntityPlayer() == null) {
return;
}
// add dictionary information
if (Dictionary.ITEMS_BREATHING_HELMET.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.breathing_helmet").getFormattedText());
}
if (Dictionary.ITEMS_FLYINSPACE.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.fly_in_space").getFormattedText());
}
if (Dictionary.ITEMS_NOFALLDAMAGE.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.no_fall_damage").getFormattedText());
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onTooltipEvent_last(final ItemTooltipEvent event) {
if (event.getEntityPlayer() == null) {
return;
}
isSneaking = event.getEntityPlayer().isSneaking();
isCreativeMode = event.getEntityPlayer().capabilities.isCreativeMode;
// cleanup the mess every mods add (notably the registry name)
Commons.cleanupTooltip(event.getToolTip());
// add block/items details
final Block block = Block.getBlockFromItem(event.getItemStack().getItem());
if (block != Blocks.AIR) {
addBlockDetails(event, block);
} else {
addItemDetails(event, event.getItemStack().getItem());
}
// add burn time details
if (WarpDriveConfig.CLIENT_TOOLTIP_BURN_TIME.isEnabled(isSneaking, isCreativeMode)) {
final int fuelEvent = ForgeEventFactory.getItemBurnTime(event.getItemStack());
final int fuelFurnace = Math.round(TileEntityFurnace.getItemBurnTime(event.getItemStack()));
final int fuelValue = fuelEvent >= 0 ? 0 : fuelFurnace;
if (fuelValue > 0) {
Commons.addTooltip(event.getToolTip(), String.format("Fuel to burn %.1f ores", fuelValue / 200.0F));
}
}
// add ore dictionary names
if (WarpDriveConfig.CLIENT_TOOLTIP_ORE_DICTIONARY_NAME.isEnabled(isSneaking, isCreativeMode)) {
final int[] idOres = OreDictionary.getOreIDs(event.getItemStack());
if (idOres.length != 0) {
Commons.addTooltip(event.getToolTip(), "Ore dictionary names:");
for (final int idOre : idOres) {
final String nameOre = OreDictionary.getOreName(idOre);
Commons.addTooltip(event.getToolTip(), "- " + nameOre);
}
}
}
}
@SuppressWarnings("deprecation")
public void addBlockDetails(final ItemTooltipEvent event, final Block block) {
// item registry name
final ResourceLocation registryNameItem = event.getItemStack().getItem().getRegistryName();
if (registryNameItem == null) {
Commons.addTooltip(event.getToolTip(), "§4Invalid item with no registry name!");
return;
}
// registry name
if (WarpDriveConfig.CLIENT_TOOLTIP_REGISTRY_NAME.isEnabled(isSneaking, isCreativeMode)) {
try {
final ResourceLocation registryNameBlock = Block.REGISTRY.getNameForObject(block);
// noinspection ConstantConditions
if (registryNameBlock != null) {
Commons.addTooltip(event.getToolTip(), "§8" + registryNameBlock);
}
} catch (final Exception exception) {
// no operation
}
}
// tool related stats
IBlockState blockState = null;
try {
blockState = block.getStateFromMeta(event.getItemStack().getItemDamage());
} catch (final AssertionError assertionError) {
// assertionError.printStackTrace();
if (!registryNameItem.toString().equals("ic2:te")) {
// noinspection ConstantConditions
WarpDrive.logger.error(String.format("Assertion error on item stack %s with state %s",
event.getItemStack(), (blockState != null) ? blockState : "-null-"));
}
}
if ( WarpDriveConfig.CLIENT_TOOLTIP_HARVESTING.isEnabled(isSneaking, isCreativeMode)
&& blockState != null ) {
try {
final String harvestTool = block.getHarvestTool(blockState);
if (harvestTool != null) {
Commons.addTooltip(event.getToolTip(), String.format("Harvest with %s (%d)",
harvestTool,
block.getHarvestLevel(blockState)));
}
} catch (final Exception exception) {
// no operation
}
}
// generic properties
if ( WarpDriveConfig.CLIENT_TOOLTIP_OPACITY.isEnabled(isSneaking, isCreativeMode)
&& blockState != null ) {
try {
Commons.addTooltip(event.getToolTip(), String.format("§8Light opacity is %d",
block.getLightOpacity(blockState)));
} catch (final Exception exception) {
// no operation
}
}
if (WarpDriveConfig.CLIENT_TOOLTIP_HARDNESS.isEnabled(isSneaking, isCreativeMode)) {
try {
Commons.addTooltip(event.getToolTip(), String.format("§8Hardness is %.1f",
(float) WarpDrive.fieldBlockHardness.get(block)));
} catch (final Exception exception) {
// no operation
}
Commons.addTooltip(event.getToolTip(), String.format("§8Explosion resistance is %.1f",
block.getExplosionResistance(null)));
}
// flammability
if (WarpDriveConfig.CLIENT_TOOLTIP_FLAMMABILITY.isEnabled(isSneaking, isCreativeMode)) {
try {
final int flammability = Blocks.FIRE.getFlammability(block);
final int fireSpread = Blocks.FIRE.getEncouragement(block);
if (flammability > 0) {
Commons.addTooltip(event.getToolTip(), String.format("§8Flammability is %d, spread %d",
flammability, fireSpread));
}
} catch (final Exception exception) {
// no operation
}
}
// fluid stats
if (WarpDriveConfig.CLIENT_TOOLTIP_FLUID.isEnabled(isSneaking, isCreativeMode)) {
try {
final Fluid fluid = FluidRegistry.lookupFluidForBlock(block);
if (fluid != null) {
if (fluid.isGaseous()) {
Commons.addTooltip(event.getToolTip(), String.format("Gaz viscosity is %d",
fluid.getViscosity()));
Commons.addTooltip(event.getToolTip(), String.format("Gaz density is %d",
fluid.getDensity()));
} else {
Commons.addTooltip(event.getToolTip(), String.format("Liquid viscosity is %d",
fluid.getViscosity()));
Commons.addTooltip(event.getToolTip(), String.format("Liquid density is %d",
fluid.getDensity()));
}
Commons.addTooltip(event.getToolTip(), String.format("Temperature is %d K",
fluid.getTemperature()));
}
} catch (final Exception exception) {
// no operation
}
}
}
public void addItemDetails(final ItemTooltipEvent event, final Item item) {
// registry name
if (WarpDriveConfig.CLIENT_TOOLTIP_REGISTRY_NAME.isEnabled(isSneaking, isCreativeMode)) {
try {
final ResourceLocation registryNameItem = Item.REGISTRY.getNameForObject(item);
if (registryNameItem == null) {
Commons.addTooltip(event.getToolTip(), "§4Invalid item with no registry name!");
return;
}
Commons.addTooltip(event.getToolTip(), "§8" + registryNameItem);
} catch (final Exception exception) {
// no operation
}
}
// (item duration can't be directly understood => out)
// durability
if (WarpDriveConfig.CLIENT_TOOLTIP_DURABILITY.isEnabled(isSneaking, isCreativeMode)) {
try {
if (event.getItemStack().isItemStackDamageable()) {
Commons.addTooltip(event.getToolTip(), String.format("Durability: %d / %d",
event.getItemStack().getMaxDamage() - event.getItemStack().getItemDamage(),
event.getItemStack().getMaxDamage()));
}
} catch (final Exception exception) {
// no operation
}
}
// armor stats
if (WarpDriveConfig.CLIENT_TOOLTIP_ARMOR.isEnabled(isSneaking, isCreativeMode)) {
try {
if (item instanceof ItemArmor) {
Commons.addTooltip(event.getToolTip(), String.format("Armor points: %d",
((ItemArmor) item).damageReduceAmount));
final ArmorMaterial armorMaterial = ((ItemArmor) item).getArmorMaterial();
Commons.addTooltip(event.getToolTip(), String.format("Enchantability: %d",
armorMaterial.getEnchantability()));
if (WarpDriveConfig.CLIENT_TOOLTIP_REPAIR_WITH.isEnabled(isSneaking, isCreativeMode)) {
final ItemStack itemStackRepair = armorMaterial.getRepairItemStack();
if (!itemStackRepair.isEmpty()) {
Commons.addTooltip(event.getToolTip(), String.format("Repair with %s",
itemStackRepair.getTranslationKey()));
}
}
}
} catch (final Exception exception) {
// no operation
}
}
}
@SubscribeEvent
public void onClientTick(final ClientTickEvent event) {
if (event.side != Side.CLIENT || event.phase != Phase.END) {

View file

@ -0,0 +1,419 @@
package cr0s.warpdrive.event;
import cr0s.warpdrive.Commons;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.Dictionary;
import cr0s.warpdrive.config.WarpDriveConfig;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.item.ItemMonsterPlacer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
public class TooltipHandler {
private static final BlockPos blockPosDummy = new BlockPos(0, -1, 0);
@SideOnly(Side.CLIENT)
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onTooltipEvent_first(final ItemTooltipEvent event) {
if (event.getEntityPlayer() == null) {
return;
}
// add dictionary information
if (Dictionary.ITEMS_BREATHING_HELMET.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.breathing_helmet").getFormattedText());
}
if (Dictionary.ITEMS_FLYINSPACE.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.fly_in_space").getFormattedText());
}
if (Dictionary.ITEMS_NOFALLDAMAGE.contains(event.getItemStack().getItem())) {
Commons.addTooltip(event.getToolTip(), new TextComponentTranslation("warpdrive.tooltip.item_tag.no_fall_damage").getFormattedText());
}
}
@SideOnly(Side.CLIENT)
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onTooltipEvent_last(final ItemTooltipEvent event) {
if (event.getEntityPlayer() == null) {
return;
}
final boolean isSneaking = event.getEntityPlayer().isSneaking();
final boolean isCreativeMode = event.getEntityPlayer().capabilities.isCreativeMode;
// cleanup the mess every mods add (notably the registry name)
cleanupTooltip(event.getToolTip(), isSneaking, isCreativeMode);
// add block/items details
final Block block = Block.getBlockFromItem(event.getItemStack().getItem());
if (block != Blocks.AIR) {
addBlockDetails(event, isSneaking, isCreativeMode, block);
} else {
addItemDetails(event, isSneaking, isCreativeMode, event.getItemStack());
}
// add burn time details
if (WarpDriveConfig.TOOLTIP_ADD_BURN_TIME.isEnabled(isSneaking, isCreativeMode)) {
final int fuelEvent = ForgeEventFactory.getItemBurnTime(event.getItemStack());
final int fuelFurnace = Math.round(TileEntityFurnace.getItemBurnTime(event.getItemStack()));
final int fuelValue = fuelEvent >= 0 ? 0 : fuelFurnace;
if (fuelValue > 0) {
Commons.addTooltip(event.getToolTip(), String.format("§8Fuel to burn %.1f ores", fuelValue / 200.0F));
}
}
// add ore dictionary names
if (WarpDriveConfig.TOOLTIP_ADD_ORE_DICTIONARY_NAME.isEnabled(isSneaking, isCreativeMode)) {
final int[] idOres = OreDictionary.getOreIDs(event.getItemStack());
if (idOres.length != 0) {
Commons.addTooltip(event.getToolTip(), "Ore dictionary names:");
for (final int idOre : idOres) {
final String nameOre = OreDictionary.getOreName(idOre);
Commons.addTooltip(event.getToolTip(), "- " + nameOre);
}
}
}
}
// remove redundant information in tooltips
private static void cleanupTooltip(@Nonnull final List<String> list, final boolean isSneaking, final boolean isCreativeMode) {
// skip empty tooltip
if (list.isEmpty()) {
return;
}
// skip if disabled
if (!WarpDriveConfig.TOOLTIP_ENABLE_DEDUPLICATION.isEnabled(isSneaking, isCreativeMode)) {
return;
}
// remove duplicates
final HashSet<String> setClean = new HashSet<>(list.size());
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
final String original = iterator.next();
final String clean = Commons.removeFormatting(original).trim().toLowerCase();
if (clean.isEmpty()) {
continue;
}
boolean doRemove = setClean.contains(clean);
for (final String key : WarpDriveConfig.TOOLTIP_CLEANUP_LIST) {
if (clean.contains(key)) {
doRemove = true;
break;
}
}
if (doRemove) {
iterator.remove();
} else {
setClean.add(clean);
}
}
// remove extra separator lines that might be resulting from the cleanup (i.e. 2 consecutive empty lines or a final empty line)
boolean wasEmpty = false;
iterator = list.iterator();
while (iterator.hasNext()) {
final String original = iterator.next();
final String clean = Commons.removeFormatting(original).trim();
// keep line with content or at least 4 spaces (for mods adding image overlays)
if ( !clean.isEmpty()
|| original.length() > 4 ) {
wasEmpty = false;
continue;
}
// only keep first empty line in a sequence
// always remove the last line when it's empty
if ( wasEmpty
|| !iterator.hasNext() ) {
iterator.remove();
}
wasEmpty = true;
}
}
@SideOnly(Side.CLIENT)
@SuppressWarnings("deprecation")
private static void addBlockDetails(@Nonnull final ItemTooltipEvent event, final boolean isSneaking, final boolean isCreativeMode, final Block block) {
// item registry name
final ResourceLocation registryNameItem = event.getItemStack().getItem().getRegistryName();
if (registryNameItem == null) {
Commons.addTooltip(event.getToolTip(), "§4Invalid item with no registry name!");
return;
}
// registry name
if (WarpDriveConfig.TOOLTIP_ADD_REGISTRY_NAME.isEnabled(isSneaking, isCreativeMode)) {
try {
final ResourceLocation registryNameBlock = Block.REGISTRY.getNameForObject(block);
// noinspection ConstantConditions
if (registryNameBlock != null) {
Commons.addTooltip(event.getToolTip(), "§8" + registryNameBlock);
}
} catch (final Exception exception) {
// no operation
}
}
// tool related stats
final IBlockState blockState = getStateForPlacement(block,
null, null,
EnumFacing.DOWN, 0.0F, 0.0F, 0.0F, event.getItemStack().getMetadata(),
null, EnumHand.MAIN_HAND);
if (WarpDriveConfig.TOOLTIP_ADD_HARVESTING.isEnabled(isSneaking, isCreativeMode)) {
try {
final String harvestTool = block.getHarvestTool(blockState);
if (harvestTool != null) {
Commons.addTooltip(event.getToolTip(), String.format("Harvest with %s (%d)",
harvestTool,
block.getHarvestLevel(blockState)));
}
} catch (final Exception exception) {
// no operation
}
}
// generic properties
if ( WarpDriveConfig.TOOLTIP_ADD_OPACITY.isEnabled(isSneaking, isCreativeMode)
&& blockState != null ) {
try {
Commons.addTooltip(event.getToolTip(), String.format("§8Light opacity is %d",
block.getLightOpacity(blockState)));
} catch (final Exception exception) {
// no operation
}
}
if (WarpDriveConfig.TOOLTIP_ADD_HARDNESS.isEnabled(isSneaking, isCreativeMode)) {
try {
Commons.addTooltip(event.getToolTip(), String.format("§8Hardness is %.1f",
(float) WarpDrive.fieldBlockHardness.get(block)));
} catch (final Exception exception) {
// no operation
}
Commons.addTooltip(event.getToolTip(), String.format("§8Explosion resistance is %.1f",
block.getExplosionResistance(null)));
}
// flammability
if (WarpDriveConfig.TOOLTIP_ADD_FLAMMABILITY.isEnabled(isSneaking, isCreativeMode)) {
try {
final int flammability = Blocks.FIRE.getFlammability(block);
final int fireSpread = Blocks.FIRE.getEncouragement(block);
if (flammability > 0) {
Commons.addTooltip(event.getToolTip(), String.format("§8Flammability is %d, spread %d",
flammability, fireSpread));
}
} catch (final Exception exception) {
// no operation
}
}
// fluid stats
if (WarpDriveConfig.TOOLTIP_ADD_FLUID.isEnabled(isSneaking, isCreativeMode)) {
try {
final Fluid fluid = FluidRegistry.lookupFluidForBlock(block);
if (fluid != null) {
if (fluid.isGaseous()) {
Commons.addTooltip(event.getToolTip(), String.format("Gaz viscosity is %d",
fluid.getViscosity()));
Commons.addTooltip(event.getToolTip(), String.format("Gaz density is %d",
fluid.getDensity()));
} else {
Commons.addTooltip(event.getToolTip(), String.format("Liquid viscosity is %d",
fluid.getViscosity()));
Commons.addTooltip(event.getToolTip(), String.format("Liquid density is %d",
fluid.getDensity()));
}
Commons.addTooltip(event.getToolTip(), String.format("Temperature is %d K",
fluid.getTemperature()));
}
} catch (final Exception exception) {
// no operation
}
}
}
// Some mods read tooltips server side for searching through them.
// However, world & placer are unknown on server side, so we're defaulting to null which doesn't always work (see stairs for example).
// IC2 is throwing assertions due to a bug somewhere...
public static IBlockState getStateForPlacement(final Block block,
final World world, final BlockPos blockPos, @Nonnull final EnumFacing facing,
final float hitX, final float hitY, final float hitZ, final int metadata,
final EntityLivingBase entityLivingBase, @Nonnull final EnumHand enumHand) {
final BlockPos blockPosToUse = blockPos != null ? blockPos : blockPosDummy;
final IBlockState blockState;
if ( (world != null && world.isRemote)
|| Thread.currentThread().getName().equals("Client thread") ) {// we're on client side, we can fallback to current player
blockState = getStateForPlacement_client(block,
world, blockPosToUse, facing,
hitX, hitY, hitZ, metadata,
entityLivingBase, enumHand);
} else {// we're server side, we try to be more 'flexible'
blockState = getStateForPlacement_safely(block,
world, blockPosToUse, facing,
hitX, hitY, hitZ, metadata,
entityLivingBase, enumHand);
}
return blockState;
}
@SideOnly(Side.CLIENT)
private static IBlockState getStateForPlacement_client(final Block block,
final World world, final BlockPos blockPos, @Nonnull final EnumFacing facing,
final float hitX, final float hitY, final float hitZ, final int metadata,
final EntityLivingBase entityLivingBase, @Nonnull final EnumHand enumHand) {
final EntityLivingBase entityLivingBaseToUse = entityLivingBase != null ? entityLivingBase : Minecraft.getMinecraft().player;
final World worldToUse = world != null ? world : entityLivingBase != null ? entityLivingBaseToUse.getEntityWorld() : null;
// during boot, even on client, player isn't defined yet, so we fallback to the server 'flexible' approach
return getStateForPlacement_safely(block,
worldToUse, blockPos, facing,
hitX, hitY, hitZ, metadata,
entityLivingBaseToUse, enumHand);
}
@SuppressWarnings("deprecation")
private static IBlockState getStateForPlacement_safely(final Block block,
final World world, final BlockPos blockPos, @Nonnull final EnumFacing facing,
final float hitX, final float hitY, final float hitZ, final int metadata,
final EntityLivingBase entityLivingBase, @Nonnull final EnumHand enumHand) {
IBlockState blockState;
try {
// world or entity might be null at this point
blockState = block.getStateForPlacement(world, blockPos, facing,
hitX, hitY, hitZ, metadata,
entityLivingBase, enumHand);
} catch (final Exception | AssertionError throwable1) {
try {
// first fallback in case world was really needed...
blockState = block.getStateFromMeta(metadata);
// just report in dev if a mandatory value was null
if (WarpDrive.isDev && (world == null || entityLivingBase == null)) {
WarpDrive.logger.error(String.format("Exception getting block state from block %s (%s %d): %s",
block,
block.getRegistryName(),
metadata,
throwable1));
}
} catch (final Exception | AssertionError throwable2) {
WarpDrive.logger.error(String.format("Exception getting block state from item stack %s (%s %d): %s",
block,
block.getRegistryName(),
metadata,
throwable1 ));
throwable1.printStackTrace();
WarpDrive.logger.error(String.format("followed by %s",
throwable2 ));
throwable2.printStackTrace();
// Final fallback to default
blockState = block.getDefaultState();
}
}
return blockState;
}
@SideOnly(Side.CLIENT)
private static void addItemDetails(final ItemTooltipEvent event, final boolean isSneaking, final boolean isCreativeMode, final ItemStack itemStack) {
final Item item = itemStack.getItem();
// registry name
if (WarpDriveConfig.TOOLTIP_ADD_REGISTRY_NAME.isEnabled(isSneaking, isCreativeMode)) {
try {
final ResourceLocation registryNameItem = Item.REGISTRY.getNameForObject(itemStack.getItem());
if (registryNameItem == null) {
Commons.addTooltip(event.getToolTip(), "§4Invalid item with no registry name!");
return;
}
Commons.addTooltip(event.getToolTip(), "§8" + registryNameItem);
} catch (final Exception exception) {
// no operation
}
}
// (item duration can't be directly understood => out)
// durability
if (WarpDriveConfig.TOOLTIP_ADD_DURABILITY.isEnabled(isSneaking, isCreativeMode)) {
try {
if (event.getItemStack().isItemStackDamageable()) {
Commons.addTooltip(event.getToolTip(), String.format("Durability: %d / %d",
event.getItemStack().getMaxDamage() - event.getItemStack().getItemDamage(),
event.getItemStack().getMaxDamage()));
}
} catch (final Exception exception) {
// no operation
}
}
// armor stats
if (WarpDriveConfig.TOOLTIP_ADD_ARMOR.isEnabled(isSneaking, isCreativeMode)) {
try {
if (item instanceof ItemArmor) {
if (WarpDrive.isDev) {// Armor points is already shown by vanilla tooltips
Commons.addTooltip(event.getToolTip(), String.format("Armor points: %d",
((ItemArmor) item).damageReduceAmount));
}
final ArmorMaterial armorMaterial = ((ItemArmor) item).getArmorMaterial();
Commons.addTooltip(event.getToolTip(), String.format("Enchantability: %d",
armorMaterial.getEnchantability()));
if (WarpDriveConfig.TOOLTIP_ADD_REPAIR_WITH.isEnabled(isSneaking, isCreativeMode)) {
final ItemStack itemStackRepair = armorMaterial.getRepairItemStack();
if (!itemStackRepair.isEmpty()) {
Commons.addTooltip(event.getToolTip(), String.format("Repair with %s",
itemStackRepair.getTranslationKey()));
}
}
}
} catch (final Exception exception) {
// no operation
}
}
// entity data
if (item instanceof ItemMonsterPlacer) {
if (WarpDriveConfig.TOOLTIP_ADD_ENTITY_ID.isEnabled(isSneaking, isCreativeMode)) {
final ResourceLocation entityId = ItemMonsterPlacer.getNamedIdFrom(itemStack);
if (entityId != null) {
Commons.addTooltip(event.getToolTip(), String.format("Entity is %s",
entityId));
} else {
Commons.addTooltip(event.getToolTip(), "Entity is §4-undefined");
}
}
}
}
}