Skip to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Draco18s

Members
  • Joined

  • Last visited

Everything posted by Draco18s

  1. Have fun with that. Having done chunk-level saved data myself, there are a lot of pitfalls.
  2. Show your icon registration method in your block class.
  3. Not all mods do, so knowing about JD-GUI is still a boon.
  4. That was the second choice block I'd including putting the field in the common proxy.
  5. IIRC, you want to override getCollisionBoundingBoxFromPool() .
  6. Note that items inside inventories that themselves don't tick (chests, actually most TileEntities, item frames) items don't get updates.
  7. JD-GUI may be in order.
  8. Redstone dust is super complicated to follow. It was hellish trying to disect the code enough to make redstone fences. Alright, starting to look at this block's problems. #1! The metadata used is 2,3,4,5 consistent with 0 and 1 being down and up. But! The isProvidingPower method uses bitwise &3 so the values don't arrayoutofbounds on Direction[], this is why you use ForgeDirection! #2! A bridge has one primary direction specified by metadata (that's fine) however, the crosswise direction can go either left to right or right to left. There's room in the metadata to handle this, but this means the blocks needs a way to know whether it is right handed or left handed (mirror images, not rotations). #3! Something is going on with figuring out that a neighboring block is providing power. I even duplicated all of the functionality in the repeater and still don't get the output I want (at best, it takes input directly from a redstone wire--and only wire--which I suppose would be fine). Correction, it takes direct power only, none of that "through a solid block" stuff (e.g. comparators and repeaters work too). That said, I have a working block!
  9. Here we go. There are a few important parts, and a few unimportant ones. Important: - hasCustomLoader() - load() Unimportant: - colorize() which handles color multiplication (I used it to colorize the overlay image but not the base). - anything dealing with invert (this was special case handling I wanted so that my grayscale overlays could be inverted white-to-black so that they could be used equally well on a dark base (such as basalt) or a light base (such as marble). scaleToSmaller() should be rewritten to be "scaleToLarger()" but it was easy to write and lets the overlay handle resource packs changing resolution size of only one texture without breaking horribly. It may not generate a good result, but it will generate a valid result. public class TextureAtlasDynamic extends TextureAtlasSprite { protected String textureBase; protected String textureOverlay; protected Color colorMulti; protected boolean invert; public TextureAtlasDynamic(String p_i1282_1_, String base, String overlay, Color color, boolean inv) { super(p_i1282_1_); textureBase = base; textureOverlay = overlay; colorMulti = color; invert = inv; } @Override public void updateAnimation() { TextureUtil.uploadTextureMipmap((int[][])this.framesTextureData.get(0), this.width, this.height, this.originX, this.originY, false, false); } @Override public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) { return true; } @Override public boolean load(IResourceManager manager, ResourceLocation location) { framesTextureData.clear(); this.frameCounter = 0; this.tickCounter = 0; ResourceLocation resource1 = new ResourceLocation(textureBase); ResourceLocation resource2 = new ResourceLocation(textureOverlay); try { TextureMap map = Minecraft.getMinecraft().getTextureMapBlocks(); resource1 = this.completeResourceLocation(map, resource1, 0); resource2 = this.completeResourceLocation(map, resource2, 0); BufferedImage buff = ImageIO.read(manager.getResource(resource1).getInputStream()); BufferedImage buff2 = ImageIO.read(manager.getResource(resource2).getInputStream()); int[] rawBase = new int[buff.getWidth()*buff.getHeight()]; int[] rawOverlay = new int[buff2.getWidth()*buff2.getHeight()]; buff.getRGB(0, 0, buff.getWidth(), buff.getHeight(), rawBase, 0, buff.getWidth()); buff2.getRGB(0, 0, buff2.getWidth(), buff2.getHeight(), rawOverlay, 0, buff2.getWidth()); int min = Math.min(buff.getWidth(),buff2.getWidth()); rawBase = scaleToSmaller(rawBase, buff.getWidth(), min); rawOverlay = scaleToSmaller(rawOverlay, buff2.getWidth(), min); width = min; height = min; int r1,g1,b1; int r2,g2,b2; float a1,a2,a3; for(int p=0; p<rawBase.length;p++) { Color c1 = new Color(rawBase[p],true); Color c2 = new Color(rawOverlay[p],true); c2 = colorize(colorMulti,c2,invert); a1 = c1.getAlpha()/255f; r1 = c1.getRed(); g1 = c1.getGreen(); b1 = c1.getBlue(); a2 = c2.getAlpha()/255f; r2 = c2.getRed(); g2 = c2.getGreen(); b2 = c2.getBlue(); a3 = a2+a1*(1-a2); if(a3 > 0) { r1 = Math.round(((r2*a2)+(r1*a1*(1-a2)))/a3); g1 = Math.round(((g2*a2)+(g1*a1*(1-a2)))/a3); b1 = Math.round(((b2*a2)+(b1*a1*(1-a2)))/a3); } else { r1 = g1 = b1 = 0; } Color c3 = new Color(r1,g1,b1,Math.round(a3*255)); rawBase[p] = c3.getRGB(); } int[][] aint = new int[1 + MathHelper.calculateLogBaseTwo(min)][]; for (int k = 0; k < aint.length; ++k) { aint[k] = rawBase; } this.framesTextureData.add(aint); } catch (IOException e) { e.printStackTrace(); int[][] aint = new int[1][]; for (int k = 0; k < 1; ++k) { aint[k] = new int[16*16]; for(int l=0; l<aint[k].length;l++) { aint[k][l] = 0xFFFFFFFF; } } width = 16; height = 16; this.framesTextureData.add(aint); } return false; } private static int[] scaleToSmaller(int[] data, int width, int min) { if(width == min) { return data; } int scale = width / min; int[] output = new int[min*min]; int j = 0; for(int i = 0; i < output.length; i++) { if(i%min == 0) { j += width; } output[i] = data[i*scale+j]; } return output; } private static ResourceLocation completeResourceLocation(TextureMap map, ResourceLocation loc, int c) { try { return (ResourceLocation)HardLib.proxy.resourceLocation.invoke(map, loc, c); //see below } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } private static Color colorize(Color cm, Color c2, boolean invert) { float[] pix = new float[3]; float[] mul = new float[3]; Color.RGBtoHSB(c2.getRed(), c2.getGreen(), c2.getBlue(),pix); Color.RGBtoHSB(cm.getRed(), cm.getGreen(), cm.getBlue(), mul); float v = (invert?1-pix[2]:pix[2]); Color c3 = new Color(Color.HSBtoRGB(mul[0], mul[1], v)); return new Color(c3.getRed(),c3.getGreen(),c3.getBlue(),c2.getAlpha()); } } The only bit that is external is the reflection which I did in my common proxy. It could have been static. public class ClientProxy extends CommonProxy { //public Method resourceLocation; in CommonProxy public void init() { Class clz = TextureMap.class; Method[] meths = clz.getDeclaredMethods(); for(Method m : meths) { if(m.getReturnType() == ResourceLocation.class) { m.setAccessible(true); resourceLocation = m; } } } And finally, registering the TextureAtlasSprite without needing events: (I had an array of 12 used for the same block) @Override @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister iconRegister) { this.icons = new IIcon[12]; if(iconRegister instanceof TextureMap) { //instanceof check, TextureMap should be the only thing that implements IIconRegister TextureMap map = (TextureMap)iconRegister; for(int o = 0; o < 12; o++) { String overlayName = "hazards:stone_overlay_"+o; String baseName = this.getTextureName(); //passed via block constructor from the block its "cloning" String regname = "hazards:"+this.getUnlocalizedName()+"_"+o; //the overlay texture map.setTextureEntry(regname, new TextureAtlasDynamic(regname,baseName,overlayName,new Color(color),inv)); icons[o] = map.getTextureExtry(regname); } } }
  10. Specifically because knowing the seed is a cheat: you could easily make a clone of the world and examine it with 3rd party tools to find minerals. That said, there IS a client side mod that can save the chunk data anyway (it can't save chest and other inventory content unless the container is opened, but that's pretty minor).
  11. Oh man are you in for a fun time tonight. Short answer: yes, two ways. 1) render the block twice 2) custom TextureAtlasSprite loading 1 is easier and found via Google ("two pass blocks"), 2 is muuuch more complicated and will need to wait for me to be at my desktop again. There's a copy on the forum here somewhere, check my user profile for threads started on the last couple of months.
  12. I think the OP wants his TileEntity to update. I've forgotten the name of the method, but it should be easy to find. Is something like doesRequireUpdates , returns a boolean and the default implementation returns false (and does nothing else).
  13. I'm sure I could code it, but you'd have to wait a few days. I'm kind of tied up.
  14. Mm. Wasn't sure if that's what that was or not. I was just falling asleep and remembered that weird little fact about how getPower works.
  15. Code you have showed contains no Keyboard.isKeyDown code.
  16. This is (almost certainly) a Forge bug. Is it the most recent version for 1.7.10? If so, report it as a bug. Try also checking the actually most latest (1.8. as well. Lex hates people who use 1.7.10 still.
  17. You have a lot of debug statements in there. When you mine a block and it doesn't drop the right thing, what does the console say? (Also, what is the name of your enchantment? This is for purposes unrelated to your bug. e.g. whatever you pass to setName() in your enchantment constructor).
  18. Don't rotate opposite. The getPower methods checks the block west and sends "west" as the side parameter. Your code thinks that "east" is where its input is when passed "west," so it asks the block east of it if it is powered, but that block asked your block, and so on. That is: the side parameter passed is not the side of YOUR block the request is coming from, but the side the REQUESTOR is checking.
  19. Because 1) Minecraft totally has that behavior natively (hint: item stack NBT is used for hardly nothing: enchantments and nametags and that's about it). 2) That's totally how code works: reading arbitrary data tags and knowing what the fuck to do with them.
  20. Is it possible? Yes. Will you have to write a whole lot of custom handling code so that you can display a youtube video inside an application that has never before needed that capability? Also yes.
  21. For fuck's sake, you're making your own variable called myPreviousFoodLevel . After you do all of your checks, you set myPreviousFoodLevel = player.getFoodStats().getFoodLevel() . Done, now it's the previous tick's food level, no client side method bullshit required.
  22. How the F would this crash without that GL rotate line? Anyway, TrashCaster is correct.
  23. Well, your rotate call is the same as the rotate call for South, so "no duh."
  24. By "serious hacks" we probably mean ASM coremodding. Should be a simple enough thing to insert an extra comparison statement into fences without completely wrecking everything. Java bytecode is not for the weak, however.
  25. How are you encoding 30 stays in only 16 values of metadata? You have 5 damage states and 6 facing states.

Important Information

By using this site, you agree to our Terms of Use.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.