diff --git a/src/main/java/vazkii/botania/api/lexicon/multiblock/IMultiblockRenderHook.java b/src/main/java/vazkii/botania/api/lexicon/multiblock/IMultiblockRenderHook.java index eeb6c45c3..6e044a00f 100644 --- a/src/main/java/vazkii/botania/api/lexicon/multiblock/IMultiblockRenderHook.java +++ b/src/main/java/vazkii/botania/api/lexicon/multiblock/IMultiblockRenderHook.java @@ -13,6 +13,7 @@ package vazkii.botania.api.lexicon.multiblock; import java.util.HashMap; import java.util.Map; +import vazkii.botania.api.lexicon.multiblock.component.MultiblockComponent; import net.minecraft.block.Block; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.world.IBlockAccess; @@ -24,6 +25,8 @@ public interface IMultiblockRenderHook { public static Map renderHooks = new HashMap(); - public void renderBlockForMultiblock(IBlockAccess world, Multiblock mb, Block block, int meta, RenderBlocks renderBlocks); + public void renderBlockForMultiblock(IBlockAccess world, Multiblock mb, Block block, int meta, RenderBlocks renderBlocks, MultiblockComponent comp, float alpha); + + public boolean needsTranslate(Block block); } diff --git a/src/main/java/vazkii/botania/api/lexicon/multiblock/Multiblock.java b/src/main/java/vazkii/botania/api/lexicon/multiblock/Multiblock.java index 655bd04bd..188bef3b9 100644 --- a/src/main/java/vazkii/botania/api/lexicon/multiblock/Multiblock.java +++ b/src/main/java/vazkii/botania/api/lexicon/multiblock/Multiblock.java @@ -11,6 +11,8 @@ package vazkii.botania.api.lexicon.multiblock; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import net.minecraft.block.Block; @@ -29,15 +31,20 @@ public class Multiblock { public List materials = new ArrayList(); public int minX, minY, minZ, maxX, maxY, maxZ, offX, offY, offZ; + + public HashMap, MultiblockComponent> locationCache = new HashMap, MultiblockComponent>(); /** * Adds a multiblock component to this multiblock. The component's x y z * coords should be pivoted to the center of the structure. */ public void addComponent(MultiblockComponent component) { + if(getComponentForLocation(component.relPos.posX, component.relPos.posY, component.relPos.posZ) != null) + throw new IllegalArgumentException("Location in multiblock already occupied"); components.add(component); changeAxisForNewComponent(component.relPos.posX, component.relPos.posY, component.relPos.posZ); calculateCostForNewComponent(component); + addComponentToLocationCache(component); } /** @@ -102,6 +109,7 @@ public class Multiblock { public void rotate(double angle) { for(MultiblockComponent comp : getComponents()) comp.rotate(angle); + updateLocationCache(); } public Multiblock copy() { @@ -149,5 +157,32 @@ public class Multiblock { public int getZSize() { return Math.abs(minZ) + Math.abs(maxZ) + 1; } + + /** + * Rebuilds the location cache + */ + public void updateLocationCache() { + locationCache.clear(); + for(MultiblockComponent comp : components) + addComponentToLocationCache(comp); + } + + /** + * Adds a single component to the location cache + */ + private void addComponentToLocationCache(MultiblockComponent comp) { + ChunkCoordinates pos = comp.getRelativePosition(); + locationCache.put(Arrays.asList( + pos.posX, + pos.posY, + pos.posZ + ), comp); + } + /** + * Gets the component for a given location + */ + public MultiblockComponent getComponentForLocation(int x, int y, int z) { + return locationCache.get(Arrays.asList(x, y, z)); + } } diff --git a/src/main/java/vazkii/botania/api/lexicon/multiblock/component/MultiblockComponent.java b/src/main/java/vazkii/botania/api/lexicon/multiblock/component/MultiblockComponent.java index d1e657040..21fbeaa4e 100644 --- a/src/main/java/vazkii/botania/api/lexicon/multiblock/component/MultiblockComponent.java +++ b/src/main/java/vazkii/botania/api/lexicon/multiblock/component/MultiblockComponent.java @@ -10,8 +10,11 @@ */ package vazkii.botania.api.lexicon.multiblock.component; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChunkCoordinates; import net.minecraft.world.World; @@ -24,11 +27,27 @@ public class MultiblockComponent { public ChunkCoordinates relPos; public final Block block; public final int meta; + public final TileEntity tileEntity; + public boolean doFancyRender; public MultiblockComponent(ChunkCoordinates relPos, Block block, int meta) { + this(relPos, block, meta, null); + } + + public MultiblockComponent(ChunkCoordinates relPos, Block block, int meta, boolean doFancyRender) { + this(relPos, block, meta, doFancyRender, null); + } + + public MultiblockComponent(ChunkCoordinates relPos, Block block, int meta, TileEntity tileEntity) { + this(relPos, block, meta, block.hasTileEntity() == (tileEntity != null), tileEntity); + } + + public MultiblockComponent(ChunkCoordinates relPos, Block block, int meta, boolean doFancyRender, TileEntity tileEntity) { this.relPos = relPos; this.block = block; this.meta = meta; + this.tileEntity = tileEntity; + this.doFancyRender = doFancyRender; } public ChunkCoordinates getRelativePosition() { @@ -63,6 +82,15 @@ public class MultiblockComponent { } public MultiblockComponent copy() { - return new MultiblockComponent(relPos, block, meta); + return new MultiblockComponent(relPos, block, meta, tileEntity); + } + + public TileEntity getTileEntity() { + return tileEntity; + } + + @SideOnly(Side.CLIENT) + public boolean shouldDoFancyRender() { + return doFancyRender; } } diff --git a/src/main/java/vazkii/botania/api/package-info.java b/src/main/java/vazkii/botania/api/package-info.java index d8a672b1f..caa19ac5a 100644 --- a/src/main/java/vazkii/botania/api/package-info.java +++ b/src/main/java/vazkii/botania/api/package-info.java @@ -1,4 +1,4 @@ -@API(owner = "Botania", apiVersion = "61", provides = "BotaniaAPI") +@API(owner = "Botania", apiVersion = "62", provides = "BotaniaAPI") package vazkii.botania.api; import cpw.mods.fml.common.API; diff --git a/src/main/java/vazkii/botania/client/core/handler/MultiblockBlockAccess.java b/src/main/java/vazkii/botania/client/core/handler/MultiblockBlockAccess.java new file mode 100644 index 000000000..0bd51a86a --- /dev/null +++ b/src/main/java/vazkii/botania/client/core/handler/MultiblockBlockAccess.java @@ -0,0 +1,132 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under the + * Botania License: http://botaniamod.net/license.php + * + * File Created @ [Aug 31, 2015, 11:40:59 PM (GMT)] + */ +package vazkii.botania.client.core.handler; + +import vazkii.botania.api.lexicon.multiblock.Multiblock; +import vazkii.botania.api.lexicon.multiblock.component.MultiblockComponent; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * This class acts as a wrapper around a block access to + * replace blocks with the blocks involved in the multiblock specified + */ +public class MultiblockBlockAccess implements IBlockAccess { + + protected IBlockAccess originalBlockAccess; + protected boolean hasBlockAccess = false; + protected Multiblock multiblock; + protected int anchorX, anchorY, anchorZ; + + @Override + public Block getBlock(int x, int y, int z) { + MultiblockComponent comp=getComponent(x, y, z); + if(comp != null) + return comp.getBlock(); + if(hasBlockAccess) + return originalBlockAccess.getBlock(x, y, z); + return Blocks.air; + } + + @Override + public TileEntity getTileEntity(int x, int y, int z) { + MultiblockComponent comp=getComponent(x, y, z); + if(comp != null) + return comp.getTileEntity(); + if(hasBlockAccess) + return originalBlockAccess.getTileEntity(x, y, z); + return null; + } + + @Override + public int getLightBrightnessForSkyBlocks(int x, int y, int z, int p_72802_4_) { + if(hasBlockAccess) + return originalBlockAccess.getLightBrightnessForSkyBlocks(x,y,z,p_72802_4_); + return 15728640; + } + + @Override + public int getBlockMetadata(int x, int y, int z) { + MultiblockComponent comp=getComponent(x, y, z); + if(comp != null) + return comp.getMeta(); + if(hasBlockAccess) + return originalBlockAccess.getBlockMetadata(x, y, z); + return 0; + } + + @Override + public int isBlockProvidingPowerTo(int x, int y, int z, int direction) { + return 0; + } + + @Override + public boolean isAirBlock(int x, int y, int z) { + MultiblockComponent comp=getComponent(x, y, z); + if(comp != null) + return false; + if(hasBlockAccess) + return originalBlockAccess.isAirBlock(x, y, z); + return true; + } + + @Override + public BiomeGenBase getBiomeGenForCoords(int x, int z) { + if(hasBlockAccess) + return originalBlockAccess.getBiomeGenForCoords(x, z); + return null; + } + + @Override + public int getHeight() { + if(hasBlockAccess) + return originalBlockAccess.getHeight(); + return 256; + } + + @Override + public boolean extendedLevelsInChunkCache() { + if(hasBlockAccess) + return originalBlockAccess.extendedLevelsInChunkCache(); + return false; + } + + @Override + public boolean isSideSolid(int x, int y, int z, ForgeDirection side, boolean _default) { + if(hasBlockAccess) + return originalBlockAccess.isSideSolid(x, y, z, side, _default); + return _default; + } + + /** + * Updates the block access to the new parameters + */ + public void update(IBlockAccess access, Multiblock mb, int anchorX, int anchorY, int anchorZ) { + this.originalBlockAccess = access; + this.multiblock = mb; + this.anchorX = anchorX; + this.anchorY = anchorY; + this.anchorZ = anchorZ; + this.hasBlockAccess = access != null; + } + + /** + * Returns the multiblock component for the coordinates, adjusted based on the anchor + */ + protected MultiblockComponent getComponent(int x, int y, int z) { + MultiblockComponent comp = multiblock.getComponentForLocation(x - anchorX, y - anchorY, z - anchorZ); + return comp; + } +} diff --git a/src/main/java/vazkii/botania/client/core/handler/MultiblockRenderHandler.java b/src/main/java/vazkii/botania/client/core/handler/MultiblockRenderHandler.java index 1abf6e12d..55786dc51 100644 --- a/src/main/java/vazkii/botania/client/core/handler/MultiblockRenderHandler.java +++ b/src/main/java/vazkii/botania/client/core/handler/MultiblockRenderHandler.java @@ -13,6 +13,7 @@ package vazkii.botania.client.core.handler; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.entity.player.EntityPlayer; @@ -22,6 +23,7 @@ import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -39,6 +41,8 @@ public final class MultiblockRenderHandler { public static boolean rendering = false; + private static MultiblockBlockAccess blockAccess = new MultiblockBlockAccess(); + private static RenderBlocks blockRender = RenderBlocks.getInstance(); public static MultiblockSet currentMultiblock; public static ChunkCoordinates anchor; @@ -77,8 +81,11 @@ public final class MultiblockRenderHandler { rendering = true; Multiblock mb = anchor != null ? currentMultiblock.getForIndex(angle) : currentMultiblock.getForEntity(player); boolean didAny = false; + + blockAccess.update(player.worldObj, mb, anchorX, anchorY, anchorZ); + for(MultiblockComponent comp : mb.getComponents()) - if(renderComponent(player.worldObj, mb, comp, anchorX, anchorY, anchorZ)) + if(renderComponentInWorld(player.worldObj, mb, comp, anchorX, anchorY, anchorZ)) didAny = true; rendering = false; @@ -89,7 +96,7 @@ public final class MultiblockRenderHandler { } } - private boolean renderComponent(World world, Multiblock mb, MultiblockComponent comp, int anchorX, int anchorY, int anchorZ) { + private boolean renderComponentInWorld(World world, Multiblock mb, MultiblockComponent comp, int anchorX, int anchorY, int anchorZ) { ChunkCoordinates pos = comp.getRelativePosition(); int x = pos.posX + anchorX; int y = pos.posY + anchorY; @@ -98,21 +105,75 @@ public final class MultiblockRenderHandler { return false; GL11.glPushMatrix(); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glTranslated(-RenderManager.renderPosX, -RenderManager.renderPosY, -RenderManager.renderPosZ); GL11.glDisable(GL11.GL_DEPTH_TEST); - GL11.glColor4f(1F, 1F, 1F, 0.4F); - GL11.glTranslated(x + 0.5 - RenderManager.renderPosX, y + 0.5 - RenderManager.renderPosY, z + 0.5 - RenderManager.renderPosZ); - Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture); - - blockRender.useInventoryTint = false; - Block block = comp.getBlock(); - if(IMultiblockRenderHook.renderHooks.containsKey(block)) - IMultiblockRenderHook.renderHooks.get(block).renderBlockForMultiblock(world, mb, block, comp.getMeta(), blockRender); - else blockRender.renderBlockAsItem(comp.getBlock(), comp.getMeta(), 1F); - GL11.glEnable(GL11.GL_DEPTH_TEST); + doRenderComponent(mb, comp, x, y, z, 0.4F); GL11.glPopMatrix(); return true; } + public static void renderMultiblockOnPage(Multiblock mb) { + GL11.glTranslated(-0.5, -0.5, -0.5); + blockAccess.update(null, mb, mb.offX, mb.offY, mb.offZ); + for(MultiblockComponent comp : mb.getComponents()) { + ChunkCoordinates pos = comp.getRelativePosition(); + doRenderComponent(mb, comp, pos.posX + mb.offX, pos.posY + mb.offY, pos.posZ + mb.offZ, 1); + } + } + + private static void doRenderComponent(Multiblock mb, MultiblockComponent comp, int x, int y, int z, float alpha) { + GL11.glPushMatrix(); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + Block block = comp.getBlock(); + int meta = comp.getMeta(); + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture); + blockRender.useInventoryTint = false; + if(block == null) + return; + if(IMultiblockRenderHook.renderHooks.containsKey(block)) { + GL11.glColor4f(1F, 1F, 1F, alpha); + IMultiblockRenderHook renderHook = IMultiblockRenderHook.renderHooks.get(block); + if(renderHook.needsTranslate(block)) { + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5); + } + renderHook.renderBlockForMultiblock(blockAccess, mb, block, comp.getMeta(), blockRender, comp, alpha); + } + else { + if(comp.shouldDoFancyRender()) { + int color = block.colorMultiplier(blockAccess, x, y, z); + float red = (float)(color >> 16 & 255) / 255.0F; + float green = (float)(color >> 8 & 255) / 255.0F; + float blue = (float)(color & 255) / 255.0F; + GL11.glColor4f(red, green, blue, alpha); + IBlockAccess oldBlockAccess = blockRender.blockAccess; + blockRender.blockAccess = blockAccess; + Tessellator tessellator = Tessellator.instance; + blockRender.renderAllFaces = true; + tessellator.startDrawingQuads(); + tessellator.disableColor(); + try { + blockRender.renderBlockByRenderType(block, x, y, z); + } + catch(Exception e) { + comp.doFancyRender = false; + } + tessellator.draw(); + blockRender.renderAllFaces = false; + blockRender.blockAccess = oldBlockAccess; + } + else { + int color = block.getRenderColor(meta); + float red = (float)(color >> 16 & 255) / 255.0F; + float green = (float)(color >> 8 & 255) / 255.0F; + float blue = (float)(color & 255) / 255.0F; + GL11.glColor4f(red, green, blue, alpha); + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5); + blockRender.renderBlockAsItem(block, meta, 1F); + } + } + GL11.glColor4f(1F, 1F, 1F, 1F); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glPopMatrix(); + } } diff --git a/src/main/java/vazkii/botania/client/render/block/RenderSpecialFlower.java b/src/main/java/vazkii/botania/client/render/block/RenderSpecialFlower.java index d4edc0f46..6de45bc66 100644 --- a/src/main/java/vazkii/botania/client/render/block/RenderSpecialFlower.java +++ b/src/main/java/vazkii/botania/client/render/block/RenderSpecialFlower.java @@ -18,6 +18,7 @@ import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import vazkii.botania.api.lexicon.multiblock.IMultiblockRenderHook; import vazkii.botania.api.lexicon.multiblock.Multiblock; +import vazkii.botania.api.lexicon.multiblock.component.MultiblockComponent; import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; public class RenderSpecialFlower implements ISimpleBlockRenderingHandler, IMultiblockRenderHook { @@ -119,11 +120,16 @@ public class RenderSpecialFlower implements ISimpleBlockRenderingHandler, IMulti } @Override - public void renderBlockForMultiblock(IBlockAccess world, Multiblock mb, Block block, int meta, RenderBlocks renderBlocks) { + public void renderBlockForMultiblock(IBlockAccess world, Multiblock mb, Block block, int meta, RenderBlocks renderBlocks, MultiblockComponent comp, float alpha) { Tessellator tess = Tessellator.instance; tess.startDrawingQuads(); drawCrossedSquares(world, block, block.getIcon(0, meta), 0, 0, 0, -0.5, -0.5, -0.5, 1F, renderBlocks); tess.draw(); } + @Override + public boolean needsTranslate(Block block) { + return true; + } + } diff --git a/src/main/java/vazkii/botania/common/lexicon/LexiconData.java b/src/main/java/vazkii/botania/common/lexicon/LexiconData.java index 15f32eefc..bf80238d6 100644 --- a/src/main/java/vazkii/botania/common/lexicon/LexiconData.java +++ b/src/main/java/vazkii/botania/common/lexicon/LexiconData.java @@ -22,6 +22,7 @@ import vazkii.botania.api.lexicon.LexiconCategory; import vazkii.botania.api.lexicon.LexiconEntry; import vazkii.botania.api.lexicon.LexiconPage; import vazkii.botania.api.lexicon.LexiconRecipeMappings; +import vazkii.botania.api.lexicon.multiblock.Multiblock; import vazkii.botania.client.lib.LibResources; import vazkii.botania.common.Botania; import vazkii.botania.common.achievement.ModAchievements; diff --git a/src/main/java/vazkii/botania/common/lexicon/page/PageMultiblock.java b/src/main/java/vazkii/botania/common/lexicon/page/PageMultiblock.java index 581764fb7..53506f494 100644 --- a/src/main/java/vazkii/botania/common/lexicon/page/PageMultiblock.java +++ b/src/main/java/vazkii/botania/common/lexicon/page/PageMultiblock.java @@ -86,11 +86,9 @@ public class PageMultiblock extends LexiconPage { GL11.glRotatef(-20F, 1, 0, 0); GL11.glRotatef(gui.getElapsedTicks(), 0, 1, 0); + + MultiblockRenderHandler.renderMultiblockOnPage(mb); - for(MultiblockComponent comp : mb.getComponents()) { - ChunkCoordinates pos = comp.getRelativePosition(); - renderBlock(comp.getBlock(), comp.getMeta(), pos.posX + mb.offX, pos.posY + mb.offY, pos.posZ + mb.offZ); - } GL11.glPopMatrix(); FontRenderer font = Minecraft.getMinecraft().fontRenderer; @@ -125,21 +123,6 @@ public class PageMultiblock extends LexiconPage { GL11.glPopMatrix(); } - public void renderBlock(Block block, int meta, int x, int y, int z) { - if(block != null) { - Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture); - - GL11.glPushMatrix(); - GL11.glTranslatef(x, y, z); - - RenderBlocks blockRender = RenderBlocks.getInstance(); - if(IMultiblockRenderHook.renderHooks.containsKey(block)) - IMultiblockRenderHook.renderHooks.get(block).renderBlockForMultiblock(Minecraft.getMinecraft().theWorld, mb, block, meta, blockRender); - else blockRender.renderBlockAsItem(block, meta, 0.8F); - GL11.glPopMatrix(); - } - } - @Override public void onOpened(IGuiLexiconEntry gui) { button = new GuiButton(101, gui.getLeft() + 30, gui.getTop() + gui.getHeight() - 50, gui.getWidth() - 60, 20, getButtonStr());