Jump to content

jeffryfisher

Members
  • Posts

    1283
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by jeffryfisher

  1. OK, I've finished upgrading my mods to 1.8. My server world is still running at 1.7.10 with my 1.7.10 version mods. I'm looking for discussion / tutorials / event handlers to help me learn how to detect and convert the world the first time a Forge 1.8 server opens it. I am having difficulty finding world conversion info in the haystack of mod conversion info. Is there even such a thing? I've given it a blind jump just to see what the issues are. After backing up my multiplayer world, I installed and ran it in recommended Forge build 1450 server. I noticed the following issues: 1) FML loader complained about 13 vanilla items missing (but none of my mods' items or blocks -- I guess I preserved naming!). However, in the game, all seemed to have been converted correctly, even cocoa. 2) Several of my mods' blocks were replaced by blocks new to version 1.8 (e.g. all of my Anystone Walls became slime blocks, and all of my Moon-phase sensors became sea-lanterns). Some other blocks disappeared completely (e.g. all of my specialized pressure-plates vanished without a trace, not even an error message in the log). It seems that new blocks are claiming block ids that my mods had been using, so saved chunks came up with these new block types in place of mine. 3) All of my mods' entities vanished. 4) Some of my mods' items were shifted by one: Ruby helm became ruby shears, ruby chestplate became ruby helm, ruby legs became ruby chestplate etc. It's like one item got deleted and then everything else was mistranslated by one. Has anyone worked on a mod (or app) that can convert an entire world (all saved chunks) to remap all mod items, blocks and entities out of the way of incoming 1.8 things? Is there a recommended technique whereby each of my mods can detect the version change and remap itself (how do I dredge up a world full of chunks to fix?) Is it even worth discussing? Is it already a foregone conclusion that a world modded in 1.7 will stay in 1.7 forever (or suffer horrendous substitutions / deletions)? As I indicated at the top, I am interested in reading about others' discussions and possible solutions, but I am (thus far) unable to find them in the haystack of mod upgrade threads. Any pointers would be much appreciated.
  2. Aha... Coincidence (or confusion?) in naming. I guess I should move the handler to my main mod class (and change the annotation). @statphantom: "onMissing" was just my own choice of method name (I had to call it something).
  3. In my FML event handler class, I subscribe to an event: @SubscribeEvent public void onMissing(FMLMissingMappingsEvent e) In my mod's postInit, I try to register the event handler class with FML: public void postInit(FMLPostInitializationEvent e) { super.postInit (e); classEventBusSubs eb = new classEventBusSubs (); classCommonBusSubs cb = new classCommonBusSubs (); MinecraftForge.EVENT_BUS.register (eb); // All of my "listeners" are in class...EventSubs, FMLCommonHandler.instance ().bus ().register (cb); // So register it on every bus until events are triggered } But FML rejects its own event as an event: How can it not be an event class??? It's an extension of class FMLEvent! What part of "event" is not being communicated here?
  4. Because one of my mods absorbed another (changing the modid on a few of my own items and blocks), I'm subscribing to the FMLMissingMappingsEvent. Besides handling my own changed names, I want to handle some missing vanilla items if I can. Most of the missing "items" are blocks that have no corresponding inventory or drop. Fire? Flowing lava? There are just four worthy of remapping. Potatoes (plural) remaps to potato (singular); likewise carrots. Cooked_fished remaps to cooked_fish. However, I'm stumped by cocoa. It looks like the cocoa item has been replaced by dye, which has subtypes, cocoa being BROWN. Looking at the remap methods in FMLMissingMappingsEvent, I don't see how to specify an item subtype. Though it's hardly vital (I can probably replace cocoa stockpiles by adventuring faster than I can figure out how to replace cocoa item stacks by programming), I am curious to know if there's a way. If not, then perhaps the FMLMissingMappingsEvent needs a remap method that conveys subtype (asserts hasSubtypes=true and then passes along a damage value). Finally, if anyone has done missing block/item remapping, I'd love to see an example or tutorial so I can check my work. Thanks!
  5. Your crash message definitely said that a 46 element array list had been violated. I think that's 36 slots of player inventory plus 9 slots of crafting area plus the one output slot. You should see how the vanilla code manages to combine those three things and then make it also combine the four armor slots.
  6. You don't need to set a break point. You already know what array was violated. The error message says you tried to access element 46 of a 0..45 array, so don't do that any more. Either make a larger array, or access a different array, or stop before index 46.
  7. The error is happening because he's poking one element beyond the end of his array. He knows what array it is, so he should be able to fix his code. Either extend the array or stop poking there (maybe he should poke a different array?). His course will depend on the purpose of the array, which he must analyze from its usage within vanilla code.
  8. When you say "looking at", do you mean having the Moon in his cross-hairs? If so, then look for an aim method. I think the moon is an entity, so you might be able to get a bead on it like any other entity. You might hunt for where mobs try to see players to get clues. Also: The graphics engine must do visibility math before deciding whether to render the moon graphically. If you can peek at its determination (client side only, and only if the player is using self point-of-view) then you can skip some maths. How and when you send a message to the server might be tricky though. Does the server even need to know? I missed the upshot of what you want to have happen when you test positive. If it's a purely visual effect, then the server doesn't need it. BTW, All line-of-sight methods will have at least one hole: If a player is in a long enough East-West tunnel right at moon-rise or set, then the tunnel can pierce the rendering distance, making the moon visible even deep underground.
  9. Are you still getting array out of bounds? Did you identify the array list that was violated? Did you find out why something used index 46 on a 46-element array? Maybe this array needs to get bigger when you add slots to the GUI.
  10. If the suspect method is being called (even indirectly) from your own code, then set the breakpoint there and step into the vanilla code.
  11. I had something like that happen when I updated 1.7 to 1.8 for a renderer for custom paintings. It turned out to be light level (everything is black if your light level function returns zero). I had been calling the wrong function to get the illumination level for each tile's pos. I ended up calling this.renderManager.worldObj.getCombinedLight(...). Find where you're setting light level and compare your light source to what's used in a comparable vanilla renderer.
  12. After upgrading my mods from 1.7.10 to 1.8, I worried that some of my own blocks and items might not carry over from my old worlds. I never expected to get errors on essential vanilla objects. However, a dozen vanilla items came up missing on my first try with an old (1.7.10) practice SP world (created at 1.6.4 I think). I've searched both Forge and Google for this phenomenon, and I haven't found much, so I haven't found guidance, and I suspect that it's happening because of something I did (perhaps long ago). Here's what the errors look like: [12:17:06] [server thread/ERROR] [FML/]: There are unidentified mappings in this world - we are going to attempt to process anyway [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:flowing_water, id 8 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:potatoes, id 142 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:cocoa, id 127 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:carrots, id 141 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:cooked_fished, id 350 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:double_wooden_slab, id 125 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:fire, id 51 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:flowing_lava, id 10 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:lava, id 11 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:water, id 9 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:end_portal, id 119 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:double_stone_slab, id 43 [12:17:06] [server thread/ERROR] [FML/]: Unidentified item: minecraft:portal, id 90 It's just these 13 items. Do these pertain to corresponding blocks, or just the item-blocks themselves? It would be weird to step into a world from which all lava had been removed. I might find diamonds under former deep-cave lava lakes I don't see any rhyme or reason for these items to cause problems. My mods don't involve any of them. Any suggestions on how to investigate? Or should I ignore the warnings and "forge" ahead? My ultimate goal is to upgrade my modded multiplayer server world. I'll back it up and see if I get similar errors there too.
  13. EntityHorse already implements IInvBasic. Is it really necessary to restate that? Modding horses is tricky. I read that horses started as somebody's mod some years ago, and then they were absorbed into vanilla. One consequence is that several things (e.g. horse armor) that should be coded elsewhere are wedged into entity horse. Private data and enums don't help, but reflection can sometimes. I think there's already a skeletal horse coded into vanilla (at least there was), but it's not used. See getHorseType() and setHorseType(). You might be able to get a lot of mileage out of what's there so you wouldn't need to copy so much code into your own class.
  14. Maybe centralized declaration could get you the easy referencing while self-registration can still fit into encapsulation... and allow some classes to perform registration before finishing construction. But I suppose each modder's structure is a matter of taste and what's comfortable.
  15. Or you could try it from the block's constructor after the constructor calls registration. I recommend leaving a comment on the call to explain the necessity of the ordering.
  16. If you explore up the constructor stack, you'll find that material doesn't do much anymore. In particular, it does not determine flammability. If you want your new block to burn, then it should override class Block's getFlammability method: /** * Chance that fire will spread and consume this block. * 300 being a 100% chance, 0, being a 0% chance. * * @param world The current world * @param pos Block position in world * @param face The face that the fire is coming from * @return A number ranging from 0 to 300 relating used to determine if the block will be consumed by fire */ public int getFlammability(IBlockAccess world, BlockPos pos, EnumFacing face) { return net.minecraft.init.Blocks.fire.getFlammability(this); } Since Blocks.fire.getFlammability() is deprecated, I don't recommend tinkering with Blocks.fire.setFireInfo() (though it might do what you want for the time being).
  17. Looks like these are out of order. The more general village event-handling or generation should be parent (or grandparent), and the more specific nether generator should be child (or grandchild). Also, your class hierarchy is somewhat hard to parse because you have both generators and event handlers with very similar names. Can any of these be collapsed into each other? In other words, can your event handler perform the generating internally? Once you've cleaned up your patterns of inheritance (and construction), your problems with uninitialized data should go away.
  18. If I'm reading this right, MapGenVillageEventHandler and your class are each extending the same parent, but they're not in line with each other. I think your class needs to extend MapGenVillageEventHandler in order to cast it into your own class. You might try casting MapGenVillageEventHandler to its parent and then casting that to your own class, but don't be surprised if bad things happen (or some data become unavailable).
  19. I'm interested in this myself (I've long wanted to improve villagers/villages, but I haven't explored their code yet). Please post some source files when you're done (or stuck again). Also let me know if you release the finished mod at Curse. If it's close enough to what I'm hoping for, I may go with it.
  20. You shouldn't need a total rewrite from scratch. Can you extend the class in question and just override a method or two? Then where your event calls the village generator, instantiate a static one of your own and call the entry method on it instead. You'd still want some kind of test for an upper surface, but it would only need maybe 16 blocks of air above solid blocks. See what kind of check is made for placing a nethergate. Anywhere the vanilla code would place a gate is probably good enough to place a village. I think it would also be fun to substitute materials to suit the nether. Let's see... Nether-brick is so dark, but it's the only fencing. On the other hand, cobble could all be replaced by quartz double-slabs (as white as quartz but as hard as cobble). Proximity to lava (including possible lava falls from above) means avoiding wood like the plague, so you might want quartz stairs for roofing. Good luck keeping the villagers out of the lava. Can't wait to find out how the zombie-pigmen treat them. Also: Was there water in the well?
  21. You might not want a range starting at zero, so you can do something like: coordY = 30 + random.nextInt (33); Also, if you just want to be related to water rather than enforcing actual contact, then you might test for biome (ocean, deep ocean, river) rather than the blocks on the many sides.
  22. Finally solved the canvas rotation. New for mc1.8, doRender's call to GlStateManager.rotate must pass (180F-orientation) instead of simply passing rotation. I have no idea why that only affected my North-South facing alt-paintings and not my East-West ones, but all directions now work correctly.
  23. Major improvement: By replacing a lighting function call, I've dispelled the blackness. Apparently a call that worked in 1.7.10 no longer works (but still compiles). The old statement is commented out, and its replacement is beneath it in this snippet: // int l = this.renderManager.worldObj.getLightFor (EnumSkyBlock.SKY, new BlockPos (i, j, k)); int l = this.renderManager.worldObj.getCombinedLight (new BlockPos (i, j, k), 0); This is within my renderer's fixLightLevel method, the equivalent of func_77008_a() in class RenderPainting. I still have a small bug, but I think I'll sort it shortly. You might be amused by this one: When I hang one of my alt paintings on an East or West wall, it displays correctly. When I hang it on a North or South wall, the pic faces the wall so that I see the "back" of the frame (my wall of glass blocks lets me see what's what from all sides).
  24. I've been following Jimi's custom painting travails with great interest. Unfortunately for me, I seem to have fallen into a pit trap that he has not already illuminated. I can see my painting items in inventory , and I can place my paintings in the world, and they read the resource file, and they render all of their quads, but they're pure black. All of the quads (front, sides, and back) are black. The texture is completely ignored even though it was read from its file and bound to its object (whatever that means). I've stepped through all relevant functions in the debugger, both for placing a painting and loading a saved world. Everything appears to be correct (callback, texture file, world coords, texture coords). I am completely buffaloed. I'm now wondering if the problem is something completely unrelated, like failing to set light level (a beautiful painting at zero light level would be black). Any hints would be appreciated, especially what to peek at in the debugger. Is there a trick to loading resources that it might be read but not used? I thought I saw the binding happen, but I might have been tricked. Source code files... classAltPainting package jrfpaintings; import io.netty.buffer.ByteBuf; import java.util.ArrayList; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityPainting; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; /** * @author Jeff Fisher * * @version 1.8: This class creates 16 complete collections (files) of 31 paintings (canvases) each. * * To make any use of the painting renderer (like being registered), we need to struggle to be a subclass * of EntityPainting. However, its constructors "do too much", and the renderer relies too much on its * enum for our liking. Being an EntityPainting may eventually get us into trouble with a client/server * packet utility too. * * Each texture file will have the same pattern of paintings (canvasses) tiled within. This will let us * use one enum's data regardless of "lot". * * The texture resource strings are defined in classRenderAltPainting. */ public class classAltPainting extends EntityPainting implements IEntityAdditionalSpawnData { public EnumAltArt canvas; // Designates a standardized patch within an indeterminate texture file. protected int lot; // Designates which of the 16 texture files, frozen by carpet color in crafting. // Called by reflection from EntityList.createEntityFromNBT // If only the client-server messaging used the same protocol... // public classAltPainting(World w) { super (w); }; // Internal constructor shared by public constructors. // protected classAltPainting(World w, BlockPos pos) { this (w); this.hangingPosition = pos; // Reach back to imitate the grandparent's xyz constructor. this.art = EnumArt.valueOf ("jrfAltArt"); this.canvas = null; // To be set by caller (larger local constructor below) } /** * Imitate EntityPainting's place-random constructor. We can't do a direct override because we need the "lot" number. Unlike * EntityPainting, we limit our candidate pool to 8 canvases searched largest to smallest. * * This constructor is called on server side to choose random canvas, which then through the magic of messaging will cause a spawn * on the client. */ public classAltPainting(World w, BlockPos pos, EnumFacing facing, int lot) { this (w, pos); // Call the common constructor this.lot = lot; ArrayList q = new ArrayList (); EnumAltArt[] v = EnumAltArt.values (); for (int p = v.length - 1; (q.size () < && (p >= 0); p-- ) { // Start at the largest and search backward this.canvas = v[p]; // Test fit this.func_174859_a (facing); // Both orients *AND* positions; *MUST* call after every canvas assignment if (this.onValidSurface ()) q.add (this.canvas); // Test depends on setDirection(); if passed, then save for later } if (!q.isEmpty ()) { setCanvas ((EnumAltArt) q.get (this.rand.nextInt (q.size ())), facing.getHorizontalIndex ()); } } /** * This constructor gets called on the client side in response to a message from the server, which constructed its own object * using a different constructor. */ @SideOnly(Side.CLIENT) public classAltPainting(World w, BlockPos pos, EnumFacing facing, int lot, String title) { this (w, pos); // Call the common constructor this.lot = lot; setCanvas (EnumAltArt.canvasNamed (title), facing.getHorizontalIndex ()); } protected void setCanvas(EnumAltArt a, int SWNE) { EnumFacing facing = EnumFacing.getHorizontal (SWNE); this.canvas = a; // Canvas must be assigned before setDirection() // Entity.setPosition is called in Vanilla where bounds box is mangled by width & height // // setSize ((float) (a.sizeX / 16), (float) (a.sizeY / 16)); this.func_174859_a (facing); // Both orients & positions; must be called after every canvas assignment } // Imitate vanilla's setting of the bounding box, but don't let vanilla code move the entity! // @Override protected void setSize(float width, float height) { if (width != this.width || height != this.height) { this.width = width; this.height = height; this.setEntityBoundingBox (new AxisAlignedBB ( // this.getEntityBoundingBox ().minX, // this.getEntityBoundingBox ().minY, // this.getEntityBoundingBox ().minZ, // this.getEntityBoundingBox ().minX + (double) this.width, // this.getEntityBoundingBox ().minY + (double) this.height, // this.getEntityBoundingBox ().minZ + (double) this.width)); // if (this.width > local_old_width && !this.firstUpdate && !this.worldObj.isRemote) { // this.moveEntity ((double) (local_old_width - this.width), 0.0D, (double) (local_old_width - this.width)); // } } } public int getLot() { // Tell which cluster of images this entity is showing return lot; } @Override public int getWidthPixels() { return this.canvas.sizeX; } @Override public int getHeightPixels() { return this.canvas.sizeY; } /** * Called when this entity is broken. Entity parameter may be null. */ public void onBroken(Entity e) { if (e instanceof EntityPlayer && ((EntityPlayer) e).capabilities.isCreativeMode) return; this.entityDropItem (new ItemStack (classAltPaintingsMod.itemAltPainting, 1, lot), 0.0F); } /** * Helper method to write subclass entity data to NBT. * * The tag itself is not sent anywhere by any of the methods in the class stack, so * we can add/replace after call to super. */ public void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT (tag); tag.setInteger ("jrfAltArtLot", this.lot); tag.setString ("Canvas", this.canvas.title); // Replace string set by super } /** * Helper method to read subclass entity data from NBT. * * Must set lot & canvas before calling super, which calls back getWidthPixels (& Height) * */ public void readEntityFromNBT(NBTTagCompound tag) { this.lot = tag.getInteger ("jrfAltArtLot"); this.canvas = EnumAltArt.canvasNamed (tag.getString ("Canvas")); super.readEntityFromNBT (tag); // Calls setDirection() after loading other data } // Writing occurs on server side. // Entity's posX, Y & Z have been set, but nothing from EntityHanging or below is set yet. // public void writeSpawnData(ByteBuf b) { // FIXME: How much of this must change? b.writeInt (this.hangingPosition.getX ()); // world tile x (+ is East) b.writeInt (this.hangingPosition.getY ()); // world tile y (+ is Up) b.writeInt (this.hangingPosition.getZ ()); // world tile z (+ is South) b.writeByte ((byte) this.field_174860_b.ordinal ()); // Facing 0-6 is D, U, N, S, W, E b.writeByte (lot); // Texture number 0-15 taken from carpet color used to craft item ByteBufUtils.writeUTF8String (b, this.canvas.title); } public void readSpawnData(ByteBuf b) { // No-op; we stole our data in classAltPaintingSpawnCallback.apply(), which then called the long constructor. } /** * This mod completely fills each 256x256 pixel image (texture file), using the same pattern of "canvases" in each. Instead of * actual painting titles, the canvases have abstract names denoting the same patch in each file. Thus, this one enum can be used * for all 16 texture files. */ public static enum EnumAltArt { Ace1("Ace1", 16, 16, 0, 0), Ace2("Ace2", 16, 16, 16, 0), Ace3("Ace3", 16, 16, 0, 16), Ace4("Ace4", 16, 16, 16, 16), Window2x1a("Window2x1a", 32, 16, 32, 0), Window2x1b("Window2x1b", 32, 16, 32, 16), Door1x2a("Door1x2a", 16, 32, 0, 32), Door1x2b("Door1x2b", 16, 32, 16, 32), Triptych("Triptych", 48, 16, 176, 0), Quad2x2a("Quad2x2a", 32, 32, 112, 0), Quad2x2b("Quad2x2b", 32, 32, 144, 0), Quad2x2c("Quad2x2c", 32, 32, 32, 32), Hex3x2a("Hex3x2a", 48, 32, 64, 0), Hexup2x3a("Hexup2x3a", 32, 48, 0, 64), Hex3x2b("Hex3x2b", 48, 32, 64, 32), Hex3x2c("Hex3x2c", 48, 32, 80, 176), Hexup2x3b("Hexup2x3b", 32, 48, 32, 64), Hex3x2d("Hex3x2d", 48, 32, 128, 176), Double4x2("Double4x2", 64, 32, 112, 32), Square3x3a("Square3x3a", 48, 48, 64, 64), Square3x3b("Square3x3b", 48, 48, 80, 208), Square3x3c("Square3x3c", 48, 48, 128, 208), Port3x4("Port3x4", 48, 64, 64, 112), Land4x3("Land4x3", 64, 48, 112, 64), Square4x4a("Square4x4a", 64, 64, 0, 112), Square4x4b("Square4x4b", 64, 64, 112, 112), Wide5x3a("Wide5x3a", 80, 48, 176, 16), Wide5x3b("Wide5x3b", 80, 48, 176, 64), Large5x4("Large5x4", 80, 64, 176, 112), Giant5x5a("Giant5x5a", 80, 80, 0, 176), Giant5x5b("Giant5x5b", 80, 80, 176, 176); // public static final int maxTitleLength = 12; public final String title; public final int sizeX; // Horizontal size in pixels public final int sizeY; // Vertical size in pixels public final int offsetX; // Pixels right from the left edge public final int offsetY; // Pixels down from top private EnumAltArt(String title, int width, int height, int offX, int offY) { this.title = title; this.sizeX = width; this.sizeY = height; this.offsetX = offX; this.offsetY = offY; } // Find the canvas by name (title) // public static EnumAltArt canvasNamed(String canvasName) { for (EnumAltArt a : EnumAltArt.values ()) { if (a.title.equals (canvasName)) return a; } return EnumAltArt.Ace1; } } } classRenderAltPainting package jrfpaintings; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.RenderPainting; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityPainting; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; import net.minecraft.world.EnumSkyBlock; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; /** * @author Jeff Fisher * * Overrides almost all of RenderPainting. That's partly because parent is tied so tightly to EntityPainting's enum and partly * because I wanted to render each painting's reverse using its underlying carpet (wool). * * However, there's nothing to be gained from accessing Minecraft's wool textures, so each is copied into one tile within its * corresponding texture file. If there's a gain here, it is from reducing the backing/edging to two tiles that can be repeated as * many times as needed (the original texture file has 16 tiles (4x4) of wood for backing & edging). * * This mod also completely fills each texture file, using the same pattern of "canvases" in each. Instead of actual painting * titles, the canvases have abstract names. * */ @SideOnly(Side.CLIENT) public class classRenderAltPainting extends RenderPainting { protected static ResourceLocation[] fileHandle = new ResourceLocation[16]; static { for (int p = 0; p < 16; p++ ) { // Compose all 16 file resource strings fileHandle[p] = new ResourceLocation (classAltPaintingsMod.MODID, String.format ("textures/painting/paintings_jrf_%02d.png", p)); } } classRenderAltPainting(RenderManager mgr) { super (mgr); } /** * Returns the domain:path location of an entity's texture file. * Called via Render.bindEntityTexture. * Because textures are cached, this will only be called the first time a file is needed. */ @Override protected ResourceLocation getEntityTexture(Entity p) { classAltPainting ap = (classAltPainting) p; return fileHandle[ap.getLot ()]; } /** * AltPainting version of painting-specific setup method */ @Override public void doRender(EntityPainting p, double posX, double posY, double posZ, float SWNE, float ignored) { float sixteenth = 0.0625F; // 1/16 classAltPainting ap = (classAltPainting) p; classAltPainting.EnumAltArt canvas = ap.canvas; int tileWidth = canvas.sizeX / 16; GL11.glPushMatrix (); GL11.glTranslated (posX, posY, posZ); // Establish drawing origin at painting's world coords GL11.glRotatef (SWNE, 0.0F, 1.0F, 0.0F); // Orient the drawing coordinate system South-West-North-East around the Y-axis GL11.glEnable (GL12.GL_RESCALE_NORMAL); this.bindEntityTexture (ap); // Open (retrieve) the corresponding texture file GL11.glScalef (sixteenth, sixteenth, sixteenth); // 16 pixels per tile (block-face) this.drawQuads (ap, canvas.sizeX, canvas.sizeY, canvas.offsetX, canvas.offsetY); GL11.glDisable (GL12.GL_RESCALE_NORMAL); GL11.glPopMatrix (); } /** * Offsets passed are pixel counts right and down from upper-left corner of the composite texture image to the upper-left corner * of a canvas within it. * * Each painting is drawn as a very flat box* having six rectangular faces. Only one face of the box is actually the painting's * object of art (what I call the "canvas"), an array of tiles (a tile covers one block) containing 16x16 pixels. Its opposite * face is the backing. In vanilla MC, the back is oak plank texture, but in this mod the backs are carpet (wool) texture in the * color that was used to craft the painting item. The other four "faces" are the thin wooden frame one world-pixel deep. * * Textures for all six faces are found in the texture file, with only the selected canvas being variable. The carpet (wool) * backing and the wood frame are repeated constants (a tile each at the right end of the top row in the texture image). * * Coords given to graphics lib are percentages right or down from upper-left corner. Drawing coords (x, y, z) are pixels (horiz, * vert, depth), with positive values meaning rightward, upward, and away (deeper into entity as viewed from in "front"). This * drawing coordinate system has already been shifted, scaled and oriented in the world so that this method can concentrate on * drawing the object independent from its position, size and facing. * * *Actually, a painting larger than 1 tile will be drawn as an array of boxes, each complete with a wooden frame on all four * edges, many of which can never be seen. For now at least, this is an unavoidable inefficiency because I'm unwilling to dive * into the Tessellator to learn how it works. */ protected void drawQuads(EntityPainting p, int pxWidth, int pxHeight, int pxOffRight, int pxOffDn) { Tessellator tess = Tessellator.getInstance (); WorldRenderer wr = tess.getWorldRenderer (); float drHalfDepth = 0.5F; // Half world-pixel depth each way from origin (painting-face versus back) /* * These two constants center the painting around the translated origin. If I am smart enough, I will incorporate this shifting * into the call to "translate" in the doRender function above (especially since we *want* the centering done on a whole-tile * basis). */ float drCenteredHoriz = (float) (-pxWidth) / 2.0F; // minus half painting px width (center painting horizontally) float drCenteredVert = (float) (-pxHeight) / 2.0F; // minus half painting px height (center painting vertically) /* * The following constants are percentage offsets right or down within the texture file's image. They address the back and frame * of the painting (5 of 6 box-faces). In the texture file, there's just one tile of carpet (wool) and one tile of wood. These * tiles are used over and over. */ float txTop = 0.0F; // Top edge of carpet or backing float txCenterPixel = 0.001953125F; // 1/512 of texture image float txTileSize = 0.0625F; // Also coord of bottom edge of top row float txCarpetLeftEdge = 0.875F; // Carpet is tile 15 of 16 in top row (1/8 of a row shy of end) float txCarpetRightEdge = txCarpetLeftEdge + txTileSize; float txWoodRightEnd = 1F; float txWoodLeftEnd = txWoodRightEnd - txTileSize; float txWoodPixel = txWoodLeftEnd + txCenterPixel; // Backing's left edge + 1/512 for (int tileColumn = 0; tileColumn < pxWidth / 16; ++tileColumn) { // Each tile column of canvas, left to right float drTileLeftEdge = drCenteredHoriz + (float) (tileColumn * 16); // float drTileRightEdge = drTileLeftEdge + 16F; float txCanvasTileRight = (float) (pxOffRight + pxWidth - tileColumn * 16) / 256.0F; float txCanvasTileLeft = (float) (pxOffRight + pxWidth - (tileColumn + 1) * 16) / 256.0F; for (int tileRow = 0; tileRow < pxHeight / 16; ++tileRow) { // Each tile in canvas column, bottom to top float drTileBottomEdge = drCenteredVert + (float) (tileRow * 16); float drTileTopEdge = drTileBottomEdge + 16F; this.fixLightLevel (p, (drTileRightEdge + drTileLeftEdge) / 2.0F, (drTileTopEdge + drTileBottomEdge) / 2.0F); float txCanvasTileBottom = (float) (pxOffDn + pxHeight - tileRow * 16) / 256.0F; // Canvas bottom minus tile+0 float txCanvasTileTop = (float) (pxOffDn + pxHeight - (tileRow + 1) * 16) / 256.0F; // Canvas bottom minus tile+1 wr.startDrawingQuads (); wr.setNormal (0.0F, 0.0F, -1.0F); // Looking at the painting ("normal" vector toward neg depth) wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txCanvasTileLeft, (double) txCanvasTileBottom); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txCanvasTileRight, (double) txCanvasTileBottom); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txCanvasTileRight, (double) txCanvasTileTop); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txCanvasTileLeft, (double) txCanvasTileTop); wr.setNormal (0.0F, 0.0F, 1.0F); // Looking at back ("normal" vector toward positive depth) wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txCarpetLeftEdge, (double) txTop); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txCarpetRightEdge, (double) txTop); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txCarpetRightEdge, (double) txTileSize); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txCarpetLeftEdge, (double) txTileSize); wr.setNormal (0.0F, 1.0F, 0.0F); // Looking down onto frame top ("normal" vector up) wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodLeftEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodRightEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodRightEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodLeftEnd, (double) txCenterPixel); wr.setNormal (0.0F, -1.0F, 0.0F); // Looking up at frame bottom ("normal" vector down) wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodLeftEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodRightEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodRightEnd, (double) txCenterPixel); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodLeftEnd, (double) txCenterPixel); wr.setNormal (-1.0F, 0.0F, 0.0F); // Looking right at left frame ("normal" vector toward left) wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTop); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTileSize); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTileSize); wr.addVertexWithUV ((double) drTileRightEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTop); wr.setNormal (1.0F, 0.0F, 0.0F); // Looking left at right frame ("normal" vector toward right) wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTop); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) (-drHalfDepth), (double) txWoodPixel, (double) txTileSize); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileBottomEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTileSize); wr.addVertexWithUV ((double) drTileLeftEdge, (double) drTileTopEdge, (double) drHalfDepth, (double) txWoodPixel, (double) txTop); tess.draw (); } } } // Sets the light level for the center of a tile. // These poor, abused coords have gone from double to int, and now they go back again. Who designed this program? // protected void fixLightLevel(EntityPainting p, float pxRight, float pxUp) { int i = MathHelper.floor_double (p.posX); int j = MathHelper.floor_double (p.posY + (double) (pxUp / 16.0F)); // Center height is always +Y int k = MathHelper.floor_double (p.posZ); switch (p.field_174860_b) { case SOUTH: // Looking South, Right-ward is Westward { i = MathHelper.floor_double (p.posX - (double) (pxRight / 16.0F)); break; } case WEST: { // Looking West k = MathHelper.floor_double (p.posZ - (double) (pxRight / 16.0F)); break; } case NORTH: { // Looking North i = MathHelper.floor_double (p.posX + (double) (pxRight / 16.0F)); break; } case EAST: // Looking East k = MathHelper.floor_double (p.posZ + (double) (pxRight / 16.0F)); break; default: System.out.println ("Oy! How'd a paintin' get on a floor or ceiling?!?"); // TODO: Punish programmer for putting painting on floor or ceiling } int l = this.renderManager.worldObj.getLightFor (EnumSkyBlock.SKY, new BlockPos (i, j, k)); int i1 = l % 65536; int j1 = l / 65536; OpenGlHelper.setLightmapTextureCoords (OpenGlHelper.lightmapTexUnit, (float) i1, (float) j1); GL11.glColor3f (1.0F, 1.0F, 1.0F); } }
  25. I'm currently upgrading my 1.7.10 paintings mod to 1.8, so I am comparing your mod to mine... amazing congruence. I hope to solve my own bug while looking for yours... You chose to extend entityHanging (imitating entityPainting entirely), while I chose to extend entityPainting and override almost everything... The reading and writing from NBT might be the only methods I didn't replace. Anyway, I watched the video you linked, and what I saw was WAD (works as designed). Paintings are designed to hang somewhat centered around the target tile, so the big ones are supposed to extend a little down and left of your aim point. The shift occurs in EntityHanging.func_174856_o() with odds and evens adjusted by func_174858_a(). If yur problem was something else, then please clarify the symptom.
×
×
  • Create New...

Important Information

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