Add more general item colouring system

This allows for other items, such as turtles, to be dyed in the future.
This also adds support for the ore dictionary, meaning you can use other
mod's dyes to colour items.
This commit is contained in:
SquidDev 2017-05-11 18:19:34 +01:00
parent 2fd01b2adf
commit 88de097c1c
9 changed files with 274 additions and 120 deletions

View File

@ -47,7 +47,6 @@
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.client.registry.ClientRegistry;
@ -515,20 +514,20 @@ public void onRenderTick( TickEvent.RenderTickEvent event )
}
}
@SideOnly(Side.CLIENT)
private static class DiskColorHandler implements IItemColor
{
private final ItemDiskLegacy disk;
@SideOnly(Side.CLIENT)
private static class DiskColorHandler implements IItemColor
{
private final ItemDiskLegacy disk;
private DiskColorHandler(ItemDiskLegacy disk)
{
this.disk = disk;
}
private DiskColorHandler( ItemDiskLegacy disk )
{
this.disk = disk;
}
@Override
public int getColorFromItemstack( @Nonnull ItemStack stack, int layer)
{
return layer == 0 ? 0xFFFFFF : disk.getColor(stack);
}
}
@Override
public int getColorFromItemstack( @Nonnull ItemStack stack, int layer )
{
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
}
}
}

View File

@ -0,0 +1,106 @@
package dan200.computercraft.shared.common;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.ColourTracker;
import dan200.computercraft.shared.util.ColourUtils;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ColourableRecipe implements IRecipe
{
@Override
public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World worldIn )
{
boolean hasColourable = false;
boolean hasDye = false;
for( int i = 0; i < inv.getSizeInventory(); i++ )
{
ItemStack stack = inv.getStackInSlot( i );
if( stack == null ) continue;
if( stack.getItem() instanceof IColouredItem )
{
if( hasColourable ) return false;
hasColourable = true;
}
else if( ColourUtils.getStackColour( stack ) >= 0 )
{
hasDye = true;
}
else
{
return false;
}
}
return hasColourable && hasDye;
}
@Nullable
@Override
public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv )
{
ItemStack colourable = null;
ColourTracker tracker = new ColourTracker();
for( int i = 0; i < inv.getSizeInventory(); ++i )
{
ItemStack stack = inv.getStackInSlot( i );
if( stack == null ) continue;
if( stack.getItem() instanceof IColouredItem )
{
colourable = stack;
}
else
{
int index = ColourUtils.getStackColour( stack );
if( index < 0 ) continue;
Colour colour = Colour.values()[ index ];
tracker.addColour( colour.getR(), colour.getG(), colour.getB() );
}
}
if( colourable == null )
{
return null;
}
return ((IColouredItem) colourable.getItem()).setColour( colourable, tracker.getColour() );
}
@Override
public int getRecipeSize()
{
return 2;
}
@Nullable
@Override
public ItemStack getRecipeOutput()
{
return null;
}
@Nonnull
@Override
public ItemStack[] getRemainingItems( @Nonnull InventoryCrafting inv )
{
ItemStack[] results = new ItemStack[ inv.getSizeInventory() ];
for( int i = 0; i < results.length; ++i )
{
ItemStack stack = inv.getStackInSlot( i );
results[ i ] = ForgeHooks.getContainerItem( stack );
}
return results;
}
}

View File

@ -0,0 +1,10 @@
package dan200.computercraft.shared.common;
import net.minecraft.item.ItemStack;
public interface IColouredItem
{
int getColour( ItemStack stack );
ItemStack setColour( ItemStack stack, int colour );
}

View File

@ -44,7 +44,7 @@ public int getDiskID( ItemStack stack )
return -1;
}
@Override
@Override
protected void setDiskID( ItemStack stack, int id )
{
if( id >= 0 )
@ -58,10 +58,18 @@ protected void setDiskID( ItemStack stack, int id )
nbt.setInteger( "diskID", id );
}
}
public int getColor( ItemStack stack )
@Override
public int getColour( ItemStack stack )
{
NBTTagCompound nbt = stack.getTagCompound();
return nbt != null && nbt.hasKey("color") ? nbt.getInteger("color") : Colour.values()[ Math.min(15, stack.getItemDamage()) ].getHex();
if( nbt != null && nbt.hasKey( "color" ) )
{
return nbt.getInteger( "color" );
}
else
{
return Colour.values()[ Math.min( 15, stack.getItemDamage() ) ].getHex();
}
}
}

View File

@ -10,6 +10,7 @@
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
@ -24,7 +25,7 @@
import java.util.List;
public class ItemDiskLegacy extends Item
implements IMedia
implements IMedia, IColouredItem
{
public ItemDiskLegacy()
{
@ -142,7 +143,8 @@ public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world )
return ComputerCraftAPI.createSaveDirMount( world, "computer/disk/" + diskID, ComputerCraft.floppySpaceLimit );
}
public int getColor( ItemStack stack )
@Override
public int getColour( ItemStack stack )
{
return Colour.Blue.getHex();
}
@ -152,4 +154,10 @@ public boolean doesSneakBypassUse( ItemStack stack, IBlockAccess world, BlockPos
{
return true;
}
@Override
public ItemStack setColour( ItemStack stack, int colour )
{
return ItemDiskExpanded.createFromIDAndColour( getDiskID( stack ), getLabel( stack ), colour );
}
}

View File

@ -8,6 +8,8 @@
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.ColourTracker;
import dan200.computercraft.shared.util.ColourUtils;
import net.minecraft.init.Items;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
@ -18,129 +20,60 @@
public class DiskRecipe implements IRecipe
{
public DiskRecipe()
{
}
@Override
public boolean matches( @Nonnull InventoryCrafting inventory, @Nonnull World world )
public boolean matches( @Nonnull InventoryCrafting inv, @Nonnull World world )
{
boolean diskFound = false;
boolean paperFound = false;
boolean redstoneFound = false;
boolean dyeFound = false;
for (int var5 = 0; var5 < inventory.getSizeInventory(); ++var5)
for( int i = 0; i < inv.getSizeInventory(); ++i )
{
ItemStack var6 = inventory.getStackInSlot(var5);
ItemStack stack = inv.getStackInSlot( i );
if (var6 != null)
if( stack != null )
{
if (var6.getItem() instanceof ItemDiskLegacy )
if( stack.getItem() == Items.PAPER )
{
if (diskFound || redstoneFound || paperFound) // make sure no redstone or paper already accepted if disk there
{
return false;
}
diskFound = true;
}
else if( var6.getItem() == Items.DYE )
{
dyeFound = true;
}
else if( var6.getItem() == Items.PAPER )
{
if(paperFound || diskFound)
{
return false;
}
if( paperFound ) return false;
paperFound = true;
}
else if (var6.getItem() == Items.REDSTONE)
else if( stack.getItem() == Items.REDSTONE )
{
if (redstoneFound || diskFound)
{
return false;
}
if( redstoneFound ) return false;
redstoneFound = true;
}
else
else if( ColourUtils.getStackColour( stack ) < 0 )
{
return false;
}
}
}
return (redstoneFound && paperFound) || (diskFound && dyeFound);
return redstoneFound && paperFound;
}
@Override
public ItemStack getCraftingResult( @Nonnull InventoryCrafting par1InventoryCrafting)
public ItemStack getCraftingResult( @Nonnull InventoryCrafting inv )
{
int diskID = -1;
String diskLabel = null;
ColourTracker tracker = new ColourTracker();
int[] var3 = new int[3];
int var4 = 0;
int var5 = 0;
ItemDiskLegacy var6;
int var7;
int var9;
float var10;
float var11;
int var17;
boolean dyeFound = false;
for (var7 = 0; var7 < par1InventoryCrafting.getSizeInventory(); ++var7)
for( int i = 0; i < inv.getSizeInventory(); ++i )
{
ItemStack var8 = par1InventoryCrafting.getStackInSlot(var7);
ItemStack stack = inv.getStackInSlot( i );
if (var8 != null)
if( stack == null ) continue;
if( stack.getItem() != Items.PAPER && stack.getItem() != Items.REDSTONE )
{
if (var8.getItem() instanceof ItemDiskLegacy )
{
var6 = (ItemDiskLegacy)var8.getItem();
diskID = var6.getDiskID( var8 );
diskLabel = var6.getLabel( var8 );
}
else if (var8.getItem() == Items.DYE)
{
dyeFound = true;
float[] var14 = Colour.values()[ var8.getItemDamage() & 0xf ].getRGB();
int var16 = (int)(var14[0] * 255.0F);
int var15 = (int)(var14[1] * 255.0F);
var17 = (int)(var14[2] * 255.0F);
var4 += Math.max(var16, Math.max(var15, var17));
var3[0] += var16;
var3[1] += var15;
var3[2] += var17;
++var5;
}
else if (!(var8.getItem() != Items.PAPER || var8.getItem() != Items.REDSTONE))
{
return null;
}
int index = ColourUtils.getStackColour( stack );
if( index < 0 ) continue;
Colour colour = Colour.values()[ index ];
tracker.addColour( colour.getR(), colour.getG(), colour.getB() );
}
}
if( !dyeFound )
{
return ItemDiskLegacy.createFromIDAndColour( diskID, diskLabel, Colour.Blue.getHex() );
}
var7 = var3[0] / var5;
int var13 = var3[1] / var5;
var9 = var3[2] / var5;
var10 = (float)var4 / (float)var5;
var11 = (float)Math.max(var7, Math.max(var13, var9));
var7 = (int)((float)var7 * var10 / var11);
var13 = (int)((float)var13 * var10 / var11);
var9 = (int)((float)var9 * var10 / var11);
var17 = (var7 << 8) + var13;
var17 = (var17 << 8) + var9;
return ItemDiskLegacy.createFromIDAndColour( diskID, diskLabel, var17 );
return ItemDiskLegacy.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.Blue.getHex() );
}
@Override
@ -157,13 +90,13 @@ public ItemStack getRecipeOutput()
@Nonnull
@Override
public ItemStack[] getRemainingItems( @Nonnull InventoryCrafting inventoryCrafting )
public ItemStack[] getRemainingItems( @Nonnull InventoryCrafting inv )
{
ItemStack[] results = new ItemStack[ inventoryCrafting.getSizeInventory() ];
for (int i = 0; i < results.length; ++i)
ItemStack[] results = new ItemStack[ inv.getSizeInventory() ];
for( int i = 0; i < results.length; ++i )
{
ItemStack stack = inventoryCrafting.getStackInSlot(i);
results[i] = net.minecraftforge.common.ForgeHooks.getContainerItem(stack);
ItemStack stack = inv.getStackInSlot( i );
results[ i ] = net.minecraftforge.common.ForgeHooks.getContainerItem( stack );
}
return results;
}

View File

@ -10,6 +10,7 @@
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.core.computer.MainThread;
import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.computer.blocks.BlockCommandComputer;
@ -276,6 +277,7 @@ private void registerItems()
RecipeSorter.register( "computercraft:impostor", ImpostorRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
RecipeSorter.register( "computercraft:impostor_shapeless", ImpostorShapelessRecipe.class, RecipeSorter.Category.SHAPELESS, "after:minecraft:shapeless" );
RecipeSorter.register( "computercraft:disk", DiskRecipe.class, RecipeSorter.Category.SHAPELESS, "after:minecraft:shapeless" );
RecipeSorter.register( "computercraft:colour", ColourableRecipe.class, RecipeSorter.Category.SHAPELESS, "after:minecraft:shapeless" );
RecipeSorter.register( "computercraft:printout", PrintoutRecipe.class, RecipeSorter.Category.SHAPELESS, "after:minecraft:shapeless" );
RecipeSorter.register( "computercraft:pocket_computer_upgrade", PocketComputerUpgradeRecipe.class, RecipeSorter.Category.SHAPELESS, "after:minecraft:shapeless" );
@ -375,6 +377,9 @@ private void registerItems()
// Disk
GameRegistry.addRecipe( new DiskRecipe() );
// Colourable items (turtles, disks)
GameRegistry.addRecipe( new ColourableRecipe() );
// Impostor Disk recipes (to fool NEI)
ItemStack paper = new ItemStack( Items.PAPER, 1 );
ItemStack redstone = new ItemStack( Items.REDSTONE, 1 );

View File

@ -0,0 +1,48 @@
package dan200.computercraft.shared.util;
/**
* A reimplementation of the colour system in {@link net.minecraft.item.crafting.RecipesArmorDyes}, but
* bundled together as an object.
*/
public class ColourTracker
{
private int total;
private int totalR;
private int totalG;
private int totalB;
private int count;
public void addColour( int r, int g, int b )
{
total += Math.max( r, Math.max( g, b ) );
totalR += r;
totalG += g;
totalB += b;
count++;
}
public void addColour( float r, float g, float b )
{
addColour( (int) (r * 255), (int) (g * 255), (int) (b * 255) );
}
public boolean hasColour()
{
return count > 0;
}
public int getColour()
{
int avgR = totalR / count;
int avgG = totalG / count;
int avgB = totalB / count;
float avgTotal = (float) total / (float) count;
float avgMax = (float) Math.max( avgR, Math.max( avgG, avgB ) );
avgR = (int) (avgR * avgTotal / avgMax);
avgG = (int) (avgG * avgTotal / avgMax);
avgB = (int) (avgB * avgTotal / avgMax);
return (avgR << 16) | (avgG << 8) | avgB;
}
}

View File

@ -0,0 +1,37 @@
package dan200.computercraft.shared.util;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.commons.lang3.ArrayUtils;
public class ColourUtils
{
private static final String[] DYES = new String[] {
"dyeBlack", "dyeRed", "dyeGreen", "dyeBrown",
"dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray",
"dyeGray", "dyePink", "dyeLime", "dyeYellow",
"dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite"
};
private static int[] ids;
public static int getStackColour( ItemStack stack )
{
if( ids == null )
{
int ids[] = ColourUtils.ids = new int[ DYES.length ];
for( int i = 0; i < DYES.length; i++ )
{
ids[ i ] = OreDictionary.getOreID( DYES[ i ] );
}
}
for( int id : OreDictionary.getOreIDs( stack ) )
{
int index = ArrayUtils.indexOf( ids, id );
if( index >= 0 ) return index;
}
return -1;
}
}