Merge pull request #1269 from thatsIch/b-1256-number-converter

Fixes #1256: Using new size logic to determine the abbreviation for a stack size
This commit is contained in:
thatsIch
2015-04-23 23:43:31 +02:00
10 changed files with 406 additions and 390 deletions
@@ -30,12 +30,21 @@ import net.minecraft.item.ItemStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.core.AEConfig;
import appeng.core.localization.GuiText;
import appeng.util.ISlimReadableNumberConverter;
import appeng.util.IWideReadableNumberConverter;
import appeng.util.ReadableNumberConverter;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class AppEngRenderItem extends RenderItem
{
private static final ReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
private static final ISlimReadableNumberConverter SLIM_CONVERTER = ReadableNumberConverter.INSTANCE;
private static final IWideReadableNumberConverter WIDE_CONVERTER = ReadableNumberConverter.INSTANCE;
public IAEItemStack aeStack;
@@ -125,11 +134,11 @@ public class AppEngRenderItem extends RenderItem
{
if( AEConfig.instance.useTerminalUseLargeFont() )
{
return NUMBER_CONVERTER.toShortHumanReadableForm( originalSize );
return SLIM_CONVERTER.toSlimReadableForm( originalSize );
}
else
{
return NUMBER_CONVERTER.toLongHumanReadableForm( originalSize );
return WIDE_CONVERTER.toWideReadableForm( originalSize );
}
}
}
@@ -37,13 +37,20 @@ import appeng.client.ClientHelper;
import appeng.core.AELog;
import appeng.tile.AEBaseTile;
import appeng.tile.crafting.TileCraftingMonitorTile;
import appeng.util.IWideReadableNumberConverter;
import appeng.util.Platform;
import appeng.util.ReadableNumberConverter;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv1
*/
public class RenderBlockCraftingCPUMonitor extends RenderBlockCraftingCPU
{
private static final ReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
private static final IWideReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
public RenderBlockCraftingCPUMonitor()
{
@@ -174,7 +181,7 @@ public class RenderBlockCraftingCPUMonitor extends RenderBlockCraftingCPU
GL11.glScalef( 1.0f / 62.0f, 1.0f / 62.0f, 1.0f / 62.0f );
final long stackSize = ais.getStackSize();
final String renderedStackSize = NUMBER_CONVERTER.toHumanReadableForm( stackSize );
final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize );
FontRenderer fr = Minecraft.getMinecraft().fontRenderer;
int width = fr.getStringWidth( renderedStackSize );
@@ -59,14 +59,21 @@ import appeng.core.AELog;
import appeng.core.localization.PlayerMessages;
import appeng.helpers.Reflected;
import appeng.me.GridAccessException;
import appeng.util.IWideReadableNumberConverter;
import appeng.util.Platform;
import appeng.util.ReadableNumberConverter;
import appeng.util.item.AEItemStack;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class PartStorageMonitor extends PartMonitor implements IPartStorageMonitor, IStackWatcherHost
{
private static final ReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
private static final IWideReadableNumberConverter NUMBER_CONVERTER = ReadableNumberConverter.INSTANCE;
IAEItemStack configuredItem;
boolean isLocked;
IStackWatcher myWatcher;
@@ -339,7 +346,7 @@ public class PartStorageMonitor extends PartMonitor implements IPartStorageMonit
GL11.glScalef( 1.0f / 62.0f, 1.0f / 62.0f, 1.0f / 62.0f );
final long stackSize = ais.getStackSize();
final String renderedStackSize = NUMBER_CONVERTER.toHumanReadableForm( stackSize );
final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize );
FontRenderer fr = Minecraft.getMinecraft().fontRenderer;
int width = fr.getStringWidth( renderedStackSize );
@@ -0,0 +1,31 @@
package appeng.util;
import javax.annotation.Nonnegative;
/**
* Limits a number converter to a char width of at max 3 characters.
* This is generally used for players, who activated the large font extension.
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public interface ISlimReadableNumberConverter
{
/**
* Converts a number into a human readable form. It will not round the number, but down it.
* Will try to cut the number down 1 decimal later, but rarely because of the 3 width limitation.
* Can only handle non negative numbers
*
* Example:
* 10000L -> 10K
* 9999L -> 9K, not 9.9K cause 4 width
*
* @param number to be converted number
*
* @return String in SI format cut down as far as possible
*/
String toSlimReadableForm( @Nonnegative long number );
}
@@ -0,0 +1,30 @@
package appeng.util;
import javax.annotation.Nonnegative;
/**
* Limits a number converter to a char width of at max 4 characters
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public interface IWideReadableNumberConverter
{
/**
* Converts a number into a human readable form. It will not round the number, but down it.
* Will try to cut the number down 1 decimal later if width can be below 4.
* Can only handle non negative numbers
*
* Example:
* 10000L -> 10K
* 9999L -> 9999
*
* @param number to be converted number
*
* @return String in SI format cut down as far as possible
*/
String toWideReadableForm( @Nonnegative long number );
}
@@ -1,6 +1,12 @@
package appeng.util;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.Format;
/**
* Converter class to convert a large number into a SI system.
*
@@ -8,7 +14,7 @@ package appeng.util;
* @version rv2
* @since rv2
*/
public enum ReadableNumberConverter
public enum ReadableNumberConverter implements ISlimReadableNumberConverter, IWideReadableNumberConverter
{
INSTANCE;
@@ -17,125 +23,82 @@ public enum ReadableNumberConverter
*/
private static final int DIVISION_BASE = 1000;
/**
* for lg(1000) = 3, just saves some calculation
*/
private static final double LOG_DIVISION_BASE = Math.log( DIVISION_BASE );
/**
* String representation of the sorted postfixes
*/
private static final char[] ENCODED_POSTFIXES = "KMGTPE".toCharArray();
/**
* if a result would be higher than this threshold,
* it is pushed into the next bigger group,
* so the display string is shorter
*/
private static final int SHORT_THRESHOLD = 100;
private final Format format;
/**
* Converts a number into a human readable form. It will not round the number, but floor it.
*
* Example: 15555L -> 15.5K
*
* @param number to be converted number
*
* @return String in SI format cut down as far as possible
* Initializes the specific decimal format with special format for negative and positive numbers
*/
public String toHumanReadableForm( long number )
ReadableNumberConverter()
{
final String sign = this.getSign( number );
final long absNumber = Math.abs( number );
final DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator( '.' );
final DecimalFormat format = new DecimalFormat( ".#;0.#" );
format.setDecimalFormatSymbols( symbols );
format.setRoundingMode( RoundingMode.DOWN );
if( absNumber < DIVISION_BASE )
return Long.toString( number );
this.format = format;
}
final int exp = (int) ( Math.log( absNumber ) / LOG_DIVISION_BASE );
final char postFix = ENCODED_POSTFIXES[exp - 1];
final int result = (int) ( absNumber / Math.pow( DIVISION_BASE, exp ) );
return String.format( "%s%d%s", sign, result, postFix );
@Override
public String toSlimReadableForm( long number )
{
return this.toReadableFormRestrictedByWidth( number, 3 );
}
/**
* Gets character representation of the sign of a number
* restricts a string representation of a number to a specific width
*
* @param number maybe signed number
* @param number to be formatted number
* @param width width limitation of the resulting number
*
* @return '-' if the number is signed, else an empty character
* @return formatted number restricted by the width limitation
*/
private String getSign( long number )
private String toReadableFormRestrictedByWidth( long number, int width )
{
if( number < 0 )
assert number >= 0;
// handles low numbers more efficiently since no format is needed
final String numberString = Long.toString( number );
int numberSize = numberString.length();
if( numberSize <= width )
return numberString;
long base = number;
double last = base * 1000;
int exponent = -1;
String postFix = "";
while( numberSize > width )
{
return "-";
}
else
{
return "";
last = base;
base /= DIVISION_BASE;
exponent++;
// adds +1 due to the postfix
numberSize = Long.toString( base ).length() + 1;
postFix = String.valueOf( ENCODED_POSTFIXES[exponent] );
}
final String withPrecision = this.format.format( last / DIVISION_BASE ) + postFix;
final String withoutPrecision = Long.toString( base ) + postFix;
final String slimResult = ( withPrecision.length() <= width ) ? withPrecision : withoutPrecision;
// post condition
assert slimResult.length() <= width;
return slimResult;
}
/**
* Converts a number into a human readable form. It will not round the number, but floor it.
* Will try to cut the number down 1 decimal earlier. This will limit the String size to 3 chars.
*
* Example: 900L -> 0.9K
*
* @param number to be converted number
*
* @return String in SI format cut down as far as possible
*/
public String toShortHumanReadableForm( long number )
@Override
public String toWideReadableForm( final long number )
{
final String sign = this.getSign( number );
final long absNumber = Math.abs( number );
if( absNumber < DIVISION_BASE )
return Long.toString( number );
final int exp = (int) ( Math.log( absNumber ) / LOG_DIVISION_BASE );
final int result = (int) ( absNumber / Math.pow( DIVISION_BASE, exp ) );
if( result >= SHORT_THRESHOLD )
{
final int shortResult = result / SHORT_THRESHOLD;
final char postFix = ENCODED_POSTFIXES[exp];
return String.format( "%s.%d%s", sign, shortResult, postFix );
}
else
{
final char postFix = ENCODED_POSTFIXES[exp - 1];
return String.format( "%s%d%s", sign, result, postFix );
}
}
/**
* Converts a number into a human readable form. It will not round the number, but floor it.
* Will try to cut the number down 1 decimal later.
*
* Example:
* 10000L -> 10K
* 9999L -> 9999
*
* @param number to be converted number
*
* @return String in SI format cut down as far as possible
*/
public String toLongHumanReadableForm( long number )
{
final String sign = this.getSign( number );
final long absNumber = Math.abs( number );
if( absNumber < 10 * DIVISION_BASE )
return Long.toString( number );
final int exp = (int) ( Math.log( absNumber / 10 ) / LOG_DIVISION_BASE );
final int result = (int) ( absNumber / Math.pow( DIVISION_BASE, exp ) );
final char postFix = ENCODED_POSTFIXES[exp - 1];
return String.format( "%s%d%s", sign, result, postFix );
return this.toReadableFormRestrictedByWidth( number, 4 );
}
}