package WayofTime.bloodmagic.util.handler.event; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.client.event.sound.PlaySoundEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.settings.KeyConflictContext; import net.minecraftforge.client.settings.KeyModifier; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent; import net.minecraftforge.fml.relauncher.ReflectionHelper; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; import WayofTime.bloodmagic.BloodMagic; import WayofTime.bloodmagic.ConfigHandler; import WayofTime.bloodmagic.annot.Handler; import WayofTime.bloodmagic.api.Constants; import WayofTime.bloodmagic.api.registry.RitualRegistry; import WayofTime.bloodmagic.api.ritual.AreaDescriptor; import WayofTime.bloodmagic.api.ritual.Ritual; import WayofTime.bloodmagic.api.ritual.RitualComponent; import WayofTime.bloodmagic.client.hud.HUDElement; import WayofTime.bloodmagic.client.render.RenderFakeBlocks; import WayofTime.bloodmagic.item.ItemRitualDiviner; import WayofTime.bloodmagic.item.ItemRitualReader; import WayofTime.bloodmagic.item.sigil.ItemSigilHolding; import WayofTime.bloodmagic.network.BloodMagicPacketHandler; import WayofTime.bloodmagic.network.SigilHoldingPacketProcessor; import WayofTime.bloodmagic.registry.ModPotions; import WayofTime.bloodmagic.tile.TileMasterRitualStone; import WayofTime.bloodmagic.util.GhostItemHelper; import WayofTime.bloodmagic.util.handler.BMKeyBinding; import WayofTime.bloodmagic.util.helper.TextHelper; import com.google.common.base.Stopwatch; import com.google.common.collect.SetMultimap; @Handler @SideOnly(Side.CLIENT) public class ClientHandler { // Quick toggle for error suppression. Set to false if you wish to hide model errors. public static final boolean SUPPRESS_ASSET_ERRORS = true; public static TextureAtlasSprite ritualStoneBlank; public static TextureAtlasSprite ritualStoneWater; public static TextureAtlasSprite ritualStoneFire; public static TextureAtlasSprite ritualStoneEarth; public static TextureAtlasSprite ritualStoneAir; public static TextureAtlasSprite ritualStoneDawn; public static TextureAtlasSprite ritualStoneDusk; public static TextureAtlasSprite blankBloodRune; public static TextureAtlasSprite stoneBrick; public static TextureAtlasSprite glowstone; public static TextureAtlasSprite bloodStoneBrick; public static TextureAtlasSprite beacon; public static TextureAtlasSprite crystalCluster; public static Minecraft minecraft = Minecraft.getMinecraft(); public static final List keyBindings = new ArrayList(); public static final List hudElements = new ArrayList(); private static TileMasterRitualStone mrsHoloTile; private static Ritual mrsHoloRitual; private static EnumFacing mrsHoloDirection; private static boolean mrsHoloDisplay; boolean doCrystalRenderTest = true; public static ResourceLocation crystalResource = new ResourceLocation(Constants.Mod.DOMAIN + "textures/entities/defaultCrystalLayer.png"); // Contrary to what your IDE tells you, this *is* actually needed. // TODO - Rewrite this "BMKeyBinding" thing. Arc what the heck were you thinking... public static final BMKeyBinding keyOpenSigilHolding = new BMKeyBinding("openSigilHolding", Keyboard.KEY_H, BMKeyBinding.Key.OPEN_SIGIL_HOLDING); public static final KeyBinding KEY_HOLDING_CYCLE_POS = new KeyBinding(Constants.Mod.MODID + "cycleHoldingPos", KeyConflictContext.IN_GAME, KeyModifier.SHIFT, Keyboard.KEY_EQUALS, Constants.Mod.NAME); public static final KeyBinding KEY_HOLDING_CYCLE_NEG = new KeyBinding(Constants.Mod.MODID + "cycleHoldingNeg", KeyConflictContext.IN_GAME, KeyModifier.SHIFT, Keyboard.KEY_MINUS, Constants.Mod.NAME); @SubscribeEvent public void onTooltipEvent(ItemTooltipEvent event) { ItemStack stack = event.getItemStack(); if (stack == null) { return; } if (GhostItemHelper.hasGhostAmount(stack)) { int amount = GhostItemHelper.getItemGhostAmount(stack); if (amount == 0) { event.getToolTip().add(TextHelper.localize("tooltip.BloodMagic.ghost.everything")); } else { event.getToolTip().add(TextHelper.localize("tooltip.BloodMagic.ghost.amount", amount)); } } } @SubscribeEvent public void onSoundEvent(PlaySoundEvent event) { EntityPlayer player = Minecraft.getMinecraft().thePlayer; if (player != null && player.isPotionActive(ModPotions.deafness)) { event.setResultSound(null); } } @SubscribeEvent public void onTextureStitch(TextureStitchEvent.Pre event) { final String BLOCKS = "blocks"; ritualStoneBlank = forName(event.getMap(), "RitualStone", BLOCKS); ritualStoneWater = forName(event.getMap(), "WaterRitualStone", BLOCKS); ritualStoneFire = forName(event.getMap(), "FireRitualStone", BLOCKS); ritualStoneEarth = forName(event.getMap(), "EarthRitualStone", BLOCKS); ritualStoneAir = forName(event.getMap(), "AirRitualStone", BLOCKS); ritualStoneDawn = forName(event.getMap(), "LightRitualStone", BLOCKS); ritualStoneDusk = forName(event.getMap(), "DuskRitualStone", BLOCKS); blankBloodRune = forName(event.getMap(), "BlankRune", BLOCKS); stoneBrick = event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/stonebrick")); glowstone = event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/glowstone")); bloodStoneBrick = forName(event.getMap(), "BloodStoneBrick", BLOCKS); beacon = event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/beacon")); crystalCluster = forName(event.getMap(), "ShardCluster", BLOCKS); } @SubscribeEvent public void render(RenderWorldLastEvent event) { EntityPlayerSP player = minecraft.thePlayer; World world = player.worldObj; if (mrsHoloTile != null) { if (world.getTileEntity(mrsHoloTile.getPos()) instanceof TileMasterRitualStone) { if (mrsHoloDisplay) renderRitualStones(mrsHoloTile, event.getPartialTicks()); else ClientHandler.setRitualHoloToNull(); } else { ClientHandler.setRitualHoloToNull(); } } if (minecraft.objectMouseOver == null || minecraft.objectMouseOver.typeOfHit != RayTraceResult.Type.BLOCK) return; TileEntity tileEntity = world.getTileEntity(minecraft.objectMouseOver.getBlockPos()); if (tileEntity instanceof TileMasterRitualStone && player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemRitualDiviner) renderRitualStones(player, event.getPartialTicks()); if (tileEntity instanceof TileMasterRitualStone && player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemRitualReader) renderRitualInformation(player, event.getPartialTicks()); } @SubscribeEvent public void onMouseEvent(MouseEvent event) { EntityPlayerSP player = Minecraft.getMinecraft().thePlayer; if (event.getDwheel() != 0 && player != null && player.isSneaking()) { ItemStack stack = player.getHeldItemMainhand(); if (stack != null) { Item item = stack.getItem(); if (item instanceof ItemSigilHolding) { cycleSigil(stack, player, event.getDwheel()); event.setCanceled(true); } } } } @SubscribeEvent public void onKey(InputEvent event) { if (!minecraft.inGameHasFocus) return; EntityPlayerSP player = Minecraft.getMinecraft().thePlayer; for (BMKeyBinding key : keyBindings) { if (key.isPressed()) key.handleKeyPress(); } if (player != null) { ItemStack stack = player.getHeldItemMainhand(); if (stack != null && stack.getItem() instanceof ItemSigilHolding) { if (KEY_HOLDING_CYCLE_POS.isPressed()) cycleSigil(stack, player, -1); else if (KEY_HOLDING_CYCLE_NEG.isPressed()) cycleSigil(stack, player, 1); } } } @SubscribeEvent public void onHudRender(RenderGameOverlayEvent.Pre event) { for (HUDElement element : hudElements) if (element.getElementType() == event.getType() && element.shouldRender(minecraft)) element.render(minecraft, event.getResolution(), event.getPartialTicks()); } // Stolen from Chisel @SubscribeEvent public void onModelBake(ModelBakeEvent event) { if (BloodMagic.isDev() && SUPPRESS_ASSET_ERRORS) return; Stopwatch stopwatch = Stopwatch.createStarted(); Map modelErrors = ReflectionHelper.getPrivateValue(ModelLoader.class, event.getModelLoader(), "loadingExceptions"); Set missingVariants = ReflectionHelper.getPrivateValue(ModelLoader.class, event.getModelLoader(), "missingVariants"); // Collect all Blood Magic model errors List errored = new ArrayList(); for (ResourceLocation modelError : modelErrors.keySet()) if (modelError.getResourceDomain().equalsIgnoreCase(Constants.Mod.MODID)) errored.add(modelError); // Collect all Blood Magic variant errors List missing = new ArrayList(); for (ModelResourceLocation missingVariant : missingVariants) if (missingVariant.getResourceDomain().equalsIgnoreCase(Constants.Mod.MODID)) missing.add(missingVariant); // Remove discovered model errors for (ResourceLocation modelError : errored) modelErrors.remove(modelError); // Remove discovered variant errors missingVariants.removeAll(missing); if (errored.size() > 0) BloodMagic.instance.getLogger().info("Suppressed {} model errors from Blood Magic.", errored.size()); if (missing.size() > 0) BloodMagic.instance.getLogger().info("Suppressed {} variant errors from Blood Magic.", missing.size()); BloodMagic.instance.getLogger().debug("Suppressed discovered model/variant errors in {}", stopwatch.stop()); } // For some reason, we need some bad textures to be listed in the Crystal and Node models. This will hide that from the end user. @SubscribeEvent public void onTextureStitch(TextureStitchEvent.Post event) { if (BloodMagic.isDev() && SUPPRESS_ASSET_ERRORS) return; Stopwatch stopwatch = Stopwatch.createStarted(); SetMultimap missingTextures = ReflectionHelper.getPrivateValue(FMLClientHandler.class, FMLClientHandler.instance(), "missingTextures"); Set badTextureDomains = ReflectionHelper.getPrivateValue(FMLClientHandler.class, FMLClientHandler.instance(), "badTextureDomains"); String mc = "minecraft"; String format = "textures/%s.png"; Set toRemove = new HashSet(); // Find our missing textures and mark them for removal. Cannot directly remove as it would cause a CME if (missingTextures.containsKey(mc)) { Set missingMCTextures = missingTextures.get(mc); for (ResourceLocation texture : missingMCTextures) if (texture.getResourcePath().equalsIgnoreCase(String.format(format, "node")) || texture.getResourcePath().equalsIgnoreCase(String.format(format, "crystal"))) toRemove.add(texture); } // Remove all our found errors missingTextures.get(mc).removeAll(toRemove); // Make sure to only remove the bad MC domain if no other textures are missing if (missingTextures.get(mc).isEmpty()) { missingTextures.keySet().remove(mc); badTextureDomains.remove(mc); } BloodMagic.instance.getLogger().debug("Suppressed required texture errors in {}", stopwatch.stop()); } private void cycleSigil(ItemStack stack, EntityPlayer player, int dWheel) { int mode = dWheel; if (!ConfigHandler.sigilHoldingSkipsEmptySlots) { mode = ItemSigilHolding.getCurrentItemOrdinal(stack); mode = dWheel < 0 ? ItemSigilHolding.next(mode) : ItemSigilHolding.prev(mode); } ItemSigilHolding.cycleToNextSigil(stack, mode); BloodMagicPacketHandler.INSTANCE.sendToServer(new SigilHoldingPacketProcessor(player.inventory.currentItem, mode)); } private static TextureAtlasSprite forName(TextureMap textureMap, String name, String dir) { return textureMap.registerSprite(new ResourceLocation(Constants.Mod.DOMAIN + dir + "/" + name)); } private void renderRitualInformation(EntityPlayerSP player, float partialTicks) { World world = player.worldObj; TileMasterRitualStone mrs = (TileMasterRitualStone) world.getTileEntity(minecraft.objectMouseOver.getBlockPos()); Ritual ritual = mrs.getCurrentRitual(); if (ritual != null) { List ranges = ritual.getListOfRanges(); for (String range : ranges) { AreaDescriptor areaDescriptor = ritual.getBlockRange(range); for (BlockPos pos : areaDescriptor.getContainedPositions(minecraft.objectMouseOver.getBlockPos())) RenderFakeBlocks.drawFakeBlock(ritualStoneBlank, pos.getX(), pos.getY(), pos.getZ(), world); } } } private void renderRitualStones(EntityPlayerSP player, float partialTicks) { World world = player.worldObj; ItemRitualDiviner ritualDiviner = (ItemRitualDiviner) player.inventory.getCurrentItem().getItem(); EnumFacing direction = ritualDiviner.getDirection(player.inventory.getCurrentItem()); Ritual ritual = RitualRegistry.getRitualForId(ritualDiviner.getCurrentRitual(player.inventory.getCurrentItem())); if (ritual == null) return; GlStateManager.pushMatrix(); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.color(1F, 1F, 1F, 0.6125F); BlockPos vec3, vX; vec3 = minecraft.objectMouseOver.getBlockPos(); double posX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks; double posY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks; double posZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks; for (RitualComponent ritualComponent : ritual.getComponents()) { vX = vec3.add(ritualComponent.getOffset(direction)); double minX = vX.getX() - posX; double minY = vX.getY() - posY; double minZ = vX.getZ() - posZ; if (!world.getBlockState(vX).isOpaqueCube()) { TextureAtlasSprite texture = null; switch (ritualComponent.getRuneType()) { case BLANK: texture = ritualStoneBlank; break; case WATER: texture = ritualStoneWater; break; case FIRE: texture = ritualStoneFire; break; case EARTH: texture = ritualStoneEarth; break; case AIR: texture = ritualStoneAir; break; case DAWN: texture = ritualStoneDawn; break; case DUSK: texture = ritualStoneDusk; break; } RenderFakeBlocks.drawFakeBlock(texture, minX, minY, minZ, world); } } GlStateManager.popMatrix(); } public static void renderRitualStones(TileMasterRitualStone masterRitualStone, float partialTicks) { EntityPlayerSP player = minecraft.thePlayer; World world = player.worldObj; EnumFacing direction = mrsHoloDirection; Ritual ritual = mrsHoloRitual; if (ritual == null) return; GlStateManager.pushMatrix(); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.color(1F, 1F, 1F, 0.5F); BlockPos vec3, vX; vec3 = masterRitualStone.getPos(); double posX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks; double posY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks; double posZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks; for (RitualComponent ritualComponent : ritual.getComponents()) { vX = vec3.add(ritualComponent.getOffset(direction)); double minX = vX.getX() - posX; double minY = vX.getY() - posY; double minZ = vX.getZ() - posZ; if (!world.getBlockState(vX).isOpaqueCube()) { TextureAtlasSprite texture = null; switch (ritualComponent.getRuneType()) { case BLANK: texture = ritualStoneBlank; break; case WATER: texture = ritualStoneWater; break; case FIRE: texture = ritualStoneFire; break; case EARTH: texture = ritualStoneEarth; break; case AIR: texture = ritualStoneAir; break; case DAWN: texture = ritualStoneDawn; break; case DUSK: texture = ritualStoneDusk; break; } RenderFakeBlocks.drawFakeBlock(texture, minX, minY, minZ, world); } } GlStateManager.popMatrix(); } public static void setRitualHolo(TileMasterRitualStone masterRitualStone, Ritual ritual, EnumFacing direction, boolean displayed) { mrsHoloDisplay = displayed; mrsHoloTile = masterRitualStone; mrsHoloRitual = ritual; mrsHoloDirection = direction; } public static void setRitualHoloToNull() { mrsHoloDisplay = false; mrsHoloTile = null; mrsHoloRitual = null; mrsHoloDirection = EnumFacing.NORTH; } protected void renderHotbarItem(int x, int y, float partialTicks, EntityPlayer player, @Nullable ItemStack stack) { if (stack != null) { float animation = (float) stack.animationsToGo - partialTicks; if (animation > 0.0F) { GlStateManager.pushMatrix(); float f1 = 1.0F + animation / 5.0F; GlStateManager.translate((float) (x + 8), (float) (y + 12), 0.0F); GlStateManager.scale(1.0F / f1, (f1 + 1.0F) / 2.0F, 1.0F); GlStateManager.translate((float) (-(x + 8)), (float) (-(y + 12)), 0.0F); } minecraft.getRenderItem().renderItemAndEffectIntoGUI(player, stack, x, y); if (animation > 0.0F) GlStateManager.popMatrix(); minecraft.getRenderItem().renderItemOverlays(minecraft.fontRendererObj, stack, x, y); } } }