package net.mcft.copy.backpacks; import java.util.Map; import com.google.common.base.Function; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.color.IItemColor; import net.minecraft.client.renderer.color.IBlockColor; import net.minecraft.client.renderer.entity.RenderPlayer; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EnumPlayerModelParts; import net.minecraft.item.ItemStack; import net.minecraft.network.datasync.DataParameter; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.model.IModel; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.ClientRegistry; 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.mcft.copy.backpacks.BackpacksContent; import net.mcft.copy.backpacks.WearableBackpacks; import net.mcft.copy.backpacks.api.BackpackHelper; import net.mcft.copy.backpacks.api.IBackpack; import net.mcft.copy.backpacks.ProxyCommon; import net.mcft.copy.backpacks.block.entity.TileEntityBackpack; import net.mcft.copy.backpacks.client.KeyBindingHandler; import net.mcft.copy.backpacks.client.RendererBackpack; import net.mcft.copy.backpacks.item.ItemBackpack; import net.mcft.copy.backpacks.misc.util.MiscUtils; import net.mcft.copy.backpacks.misc.util.NbtUtils; import net.mcft.copy.backpacks.misc.util.ReflectUtils; @SideOnly(Side.CLIENT) public class ProxyClient extends ProxyCommon { public static IBakedModel MODEL_BACKPACK; public static IBakedModel MODEL_BACKPACK_TOP; public static IBakedModel MODEL_BACKPACK_STRAPS; @Override public void preInit() { super.preInit(); MinecraftForge.EVENT_BUS.register(new KeyBindingHandler()); if (BackpacksContent.BACKPACK != null) { ModelLoader.setCustomModelResourceLocation(BackpacksContent.BACKPACK, 0, new ModelResourceLocation("wearablebackpacks:backpack", "inventory")); } } @Override public void init() { super.init(); Minecraft mc = Minecraft.getMinecraft(); if (BackpacksContent.BACKPACK != null) { mc.getBlockColors().registerBlockColorHandler(BLOCK_COLOR, MiscUtils.getBlockFromItem(BackpacksContent.BACKPACK)); mc.getItemColors().registerItemColorHandler(ITEM_COLOR, BackpacksContent.BACKPACK); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityBackpack.class, new RendererBackpack.TileEntity()); } Map<String, RenderPlayer> skinMap = mc.getRenderManager().getSkinMap(); skinMap.get("default").addLayer(new RendererBackpack.Layer()); skinMap.get("slim").addLayer(new RendererBackpack.Layer()); // TODO: Register layer renderers for supported entities. } // Lots of code just to disable capes when backpacks are equipped! private static DataParameter<Byte> PLAYER_MODEL_FLAG = ReflectUtils.get(EntityPlayer.class, "PLAYER_MODEL_FLAG", "field_184827_bp"); /** Sets whether the player is currently wearing the specified model part. * This is the opposite of the {@link EntityPlayer#isWearing} method. */ private static void setWearing(EntityPlayer player, EnumPlayerModelParts part, boolean value) { byte current = player.getDataManager().get(PLAYER_MODEL_FLAG).byteValue(); if (value) current |= part.getPartMask(); else current &= ~part.getPartMask(); player.getDataManager().set(PLAYER_MODEL_FLAG, current); } private boolean _disabledCape = false; @SubscribeEvent(priority=EventPriority.LOWEST) public void onRenderPlayerPre(RenderPlayerEvent.Pre event) { EntityPlayer player = event.getEntityPlayer(); if ((BackpackHelper.getBackpack(player) == null) || !player.isWearing(EnumPlayerModelParts.CAPE)) return; // Disable player rendering for players with equipped backpacks // by temporarily setting whether they are wearing it to false. setWearing(player, EnumPlayerModelParts.CAPE, false); _disabledCape = true; } @SubscribeEvent(priority=EventPriority.HIGHEST) public void onRenderPlayerPost(RenderPlayerEvent.Post event) { if (!_disabledCape) return; // Reenable cape rendering if it was disabled in the EntityPlayer player = event.getEntityPlayer(); setWearing(player, EnumPlayerModelParts.CAPE, true); _disabledCape = false; } // Model related private static final Function<ResourceLocation, TextureAtlasSprite> TEXTURE_GETTER = new Function<ResourceLocation, TextureAtlasSprite>() { public TextureAtlasSprite apply(ResourceLocation location) { return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString()); } }; @SubscribeEvent @SideOnly(Side.CLIENT) public void onModelBake(ModelBakeEvent event) { MODEL_BACKPACK = bakeBlockModel("wearablebackpacks:block/backpack"); MODEL_BACKPACK_TOP = bakeBlockModel("wearablebackpacks:block/backpack_top"); MODEL_BACKPACK_STRAPS = bakeBlockModel("wearablebackpacks:block/backpack_straps"); } static IBakedModel bakeBlockModel(String location) { IModel model = getModel(new ResourceLocation(location)); return model.bake(model.getDefaultState(), DefaultVertexFormats.BLOCK, TEXTURE_GETTER); } static IModel getModel(ResourceLocation location) { try { IModel model = ModelLoaderRegistry.getModel(location); if (model == null) WearableBackpacks.LOG.error("Model " + location + " is missing! THIS WILL CAUSE A CRASH!"); return model; } catch (Exception e) { e.printStackTrace(); return null; } } // IBlockColor and IItemColor implementations public static final IBlockColor BLOCK_COLOR = new IBlockColor() { @Override public int colorMultiplier(IBlockState state, IBlockAccess worldIn, BlockPos pos, int tintIndex) { ItemStack stack = null; if ((worldIn != null) && (pos != null)) { IBackpack backpack = BackpackHelper.getBackpack(worldIn.getTileEntity(pos)); if (backpack != null) stack = backpack.getStack(); } return ITEM_COLOR.getColorFromItemstack(stack, tintIndex); } }; public static final IItemColor ITEM_COLOR = new IItemColor() { @Override public int getColorFromItemstack(ItemStack stack, int tintIndex) { // TODO: Make this work for different default colors / non-dyeable backpacks. return NbtUtils.get(stack, ItemBackpack.DEFAULT_COLOR, "display", "color"); } }; }