Jump to content

jeffryfisher

Members
  • Posts

    1283
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by jeffryfisher

  1. Since you're just filling color, you might be able to gain something from seeing how potions render the fill color in their bottles (but since they're items, not blocks, you might need to write your own abstract class to mimic colored items). Also look at how grass changes color in different biomes. Metadata is still limited to 4 data bits (16 values 0-15), so storing 14x5 (70 values) is slightly awkward. You might do an abstract class that extends Block and defines your 14 hues (the best use of 16 possible metadata values), then extend it to 5 actual block classes (your 5 brightness levels). In this scheme, your block classes would be darker, dark, normal, light and lighter. Each would inherit your hue definitions from the parent abstract class. You'll need an item block (or five) to deal with inventory. PS: I wonder how far you can get with vanilla stained glass blocks back-lit by lamps with five brightness settings (probably not far since glass blocks have such low hue saturation).
  2. Besides injecting new enum values, you'd need to store some pixels somewhere... and then render them, and a frame, and the back. The vanilla paintings are all patches of a single 256x256 png file, and I don't recommend doing anything to it. Departing from that file probably means making a custom renderer. There's another recent thread about paintings, and it has some java. I'm not sure what you mean by "what another block is looking at", but it sounds interesting. As long as what you want to display will fit into 16x16 pixels per cube face, there should be a way to get the world info and render it.
  3. I've started upgrading my own paintings mod to 1.8 (so many red X's!). Though I am still contending with a new pattern of deobfucated names (there have been changes in both directions that have broken my code from 1.7.10), I have found some clues in my old code. One is the declaration of my entity class: public class classAltPainting extends EntityPainting implements IEntityAdditionalSpawnData { The first thing I notice is that I settled (in 1.7) on extending EntityPainting instead of EntityHanging. I recall wrestling with that decision, but I can't for the life of me recall what factor(s) made up my mind. The second thing I notice is the implementation of IEntityAdditionalSpawnData. I think this has something to do with the fact that my painting come in 16 whole collections of paintings, not just one like the vanilla set. However, this aspect of my mod delves into reflection, so I haven't sorted it yet. I think my custom renderer is sorted. I had to parlay my Tesselator into a WorldRenderer It starts like this: @SideOnly(Side.CLIENT) public class classRenderAltPainting extends RenderPainting {... And its drawQuads method starts like this: protected void drawQuads(EntityPainting p, int pxWidth, int pxHeight, int pxOffRight, int pxOffDn) { Tessellator tess = Tessellator.getInstance (); WorldRenderer wr = tess.getWorldRenderer (); All of the graphics methods (e.g. adding vertexes) are called via the wr; only the "draw" at the end is called via tesselator itself. None of this has been test-run in 1.8 yet because there are still some red X's to iron out. I'll let you know if I make any more discoveries.
  4. I just did a strict test: Create a new SP world with my 1st mod, quit-save, then add my 2nd mod and restart the game (none of this in Eclipse). My custom ore generated in the 1st run was still itself after reloading, so we don't have a general bug (there would probably be much more discussion by others if we had). I think that there are some finicky rules regarding edits that we need to nail down. I've been doing my best to religiously preserve block names from 1.7 so my modded world can be upgraded to 1.8. However, I may need to restore it from backup a couple times before I get it right. If I do, and if I find the grind spot in the code where identity can be messed up, I'll post here again with notes on pitfalls to be avoided.
  5. Although you're no longer using reflection, I'd like to clarify something from your OP. You had this: try { field = Class.forName("net.minecraft.entity.EntityLivingBase").getDeclaredField("swingProgressInt"); field.setAccessible(true); field.setInt(arg0, 4); } catch... If I understand reflection correctly, then it is only necessary to getDeclaredField once and setAccessible once (perhaps in a constructor). Later, one may use the field to operate upon instances of its class to make value assignments many times. Do I have that right?
  6. Build 1506 is so brand-spanking new that it might have a bug in it. Try again with (recommended) build 1450 (the one with a solid star beside it) and see if you get better results.
  7. If you leave out the annotation, then you won't be warned if you miss your target (misspell the method name, get the mixed case name wrong, use the wrong types for the parameters). When you first write a program, you'll probably get it right without warnings. However, as a program ages, things can change. The parent's method might change, so you'd like warnings to pop up on supposed overrides. You might change a type somewhere, so you'd like to be warned that it no longer fits where needed. So, the annotation is not *needed*, but you want to put it in wherever it fits so that you'll get a reminder whenever you (or vanilla code) might do something that would break its promise. Note: There are a whole slew of vanilla methods (mostly involving block states) that changed between 1.7 and 1.8. Because I religiously annotated all of my overrides, I am now being alerted to each and every mismatch as I upgrade my mods to 1.8.
  8. I *finally* got this to work :'( Here's my (abstract) block class, which finishes with some ugly guts shamelessly copy-pasted from vanilla's BlockWall class: /** * Once upon a time (before MC v1., this could be a simple subclass of BlockWall, inheriting many useful methods. Sadly, v1.8 * screwed that up with its egregious implementation of properties (featuring Cartesian products). * * The design now imitates the useful parts of BlockWall, replacing its properties and setting them up for Forge's enhanced json * reader. * * Being a departure from BlockWall, this becomes the extensible (abstract) class from which two or more concrete classes may be * derived to provide a wide variety of skins on walls (including the original cobble and mossy cobble). */ package jrfwalls; // import static net.minecraftforge.common.util.ForgeDirection.UP; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockFenceGate; import net.minecraft.block.BlockWall; import net.minecraft.block.material.Material; import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.PropertyInteger; import net.minecraft.block.state.BlockState; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumWorldBlockLayer; import net.minecraft.world.Explosion; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; // @SuppressWarnings("rawtypes") public abstract class classAbstractWall extends Block { public static final PropertyInteger GEOMETRY = PropertyInteger.create ("geometry", 0, 17); public static final PropertyInteger SKIN = PropertyInteger.create ("skin", 0, 15); public String[] subName; // Block subtype names defined in each concrete class, copied into ItemBlock // public classItemWall itemblockAnystoneWall; public classAbstractWall(String name, String[] subNameArray) { super (Material.rock); this.setDefaultState (this.getDefaultState ().withProperty (GEOMETRY, 17)); this.setUnlocalizedName (name); this.subName = subNameArray; this.setCreativeTab (CreativeTabs.tabBlock); classAnystoneWallsMod.regBlock (this, classItemWall.class); this.setHardness (1.5F); // Default to stone this.setResistance (10.0F); // Ditto (after auto-tripling) this.setStepSound (soundTypePiston); // Ditto } // Called from ItemBlock to name an item (stack) subtype in menu or inventory or drops public String getUnlocalizedName(int meta) { // return classJRFmod.cutName(getUnlocalizedName ()) + "." + subName[meta]; return getUnlocalizedName () + "." + subName[meta]; } /** * returns a list of blocks with the same ID, but different meta (eg: wood returns 4 blocks) */ @Override @SideOnly(Side.CLIENT) public void getSubBlocks(Item i, CreativeTabs t, List list) { for (int meta = 0; meta <= 15; meta++ ) { list.add (new ItemStack (i, 1, meta)); } } // Our replacement (abstract) wall class has only two properties // @Override protected BlockState createBlockState() { return new BlockState (this, new IProperty[] { GEOMETRY, SKIN }); } /** * Convert the given metadata into a BlockState for this Block */ @Override public IBlockState getStateFromMeta(int meta) { // Block state starts with metadata being injected into default geometry return this.getDefaultState ().withProperty (SKIN, meta); } /** * Get the actual Block state of this Block at the given position. This applies properties not visible in the * metadata, such as fence connections. */ @Override public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { int g = this.canConnectTo (worldIn, pos.west ()) ? 1 : 0; if (this.canConnectTo (worldIn, pos.south ())) g += 2; // state parm should arrive with meta already in it if (this.canConnectTo (worldIn, pos.north ())) { g += 4; } if (this.canConnectTo (worldIn, pos.east ())) { g += 8; // If that makes 9, then we're (E + W) a non post straight unless connected above if (g == 9 && !worldIn.isAirBlock (pos.up ())) g = 17; } else { // We din't add 8, so we might be only 6 (N + S), also low-straight looking up if (g == 6 && !worldIn.isAirBlock (pos.up ())) g = 16; } return state.withProperty (GEOMETRY, g); // ...so we just add geometry } /** * Convert the BlockState into the correct metadata value */ @Override public int getMetaFromState(IBlockState state) { return ((Integer) state.getValue (SKIN)).intValue (); } /** * Get the damage value that this Block should drop */ @Override public int damageDropped(IBlockState state) { return getMetaFromState (state); } @Override @SideOnly(Side.CLIENT) public EnumWorldBlockLayer getBlockLayer() { return EnumWorldBlockLayer.CUTOUT; } @Override abstract public float getExplosionResistance(World world, BlockPos pos, Entity exploder, Explosion explosion); // Imitate Block class until the call to abstract method @Override public int getLightValue(IBlockAccess world, BlockPos pos) { IBlockState bs = world.getBlockState (pos); Block block = bs.getBlock (); if (block != this) { // Some other block type replaced me? return block.getLightValue (world, pos); } return getLightValue (this.getMetaFromState (bs)); // Here's where we do something extra } abstract int getLightValue(int meta); /** * Return whether this wall can connect to an adjacent block at pos. */ public boolean canConnectTo(IBlockAccess worldIn, BlockPos pos) { Block block = worldIn.getBlockState (pos).getBlock (); if (block == Blocks.barrier) return false; if (block instanceof classAbstractWall || block instanceof BlockWall || block instanceof BlockFenceGate) return true; if (block.isFullCube () && !block.isPassable (worldIn, pos)) { return block.getMaterial () != Material.gourd; } else { return false; } } /** * All methods from here down are unaltered copies from class BlockWall. Do not mess! */ @Override public boolean canPlaceTorchOnTop(IBlockAccess world, BlockPos pos) { return true; } @Override public boolean isFullCube() { return false; } @Override public boolean isOpaqueCube() { return false; } @Override public AxisAlignedBB getCollisionBoundingBox(World worldIn, BlockPos pos, IBlockState state) { this.setBlockBoundsBasedOnState (worldIn, pos); this.maxY = 1.5D; return super.getCollisionBoundingBox (worldIn, pos, state); } @SideOnly(Side.CLIENT) public boolean shouldSideBeRendered(IBlockAccess worldIn, BlockPos pos, EnumFacing side) { return side == EnumFacing.DOWN ? super.shouldSideBeRendered (worldIn, pos, side) : true; } @Override public void setBlockBoundsBasedOnState(IBlockAccess worldIn, BlockPos pos) { boolean flag = this.canConnectTo (worldIn, pos.north ()); boolean flag1 = this.canConnectTo (worldIn, pos.south ()); boolean flag2 = this.canConnectTo (worldIn, pos.west ()); boolean flag3 = this.canConnectTo (worldIn, pos.east ()); float f = 0.25F; float f1 = 0.75F; float f2 = 0.25F; float f3 = 0.75F; float f4 = 1.0F; if (flag) { f2 = 0.0F; } if (flag1) { f3 = 1.0F; } if (flag2) { f = 0.0F; } if (flag3) { f1 = 1.0F; } if (flag && flag1 && !flag2 && !flag3) { f4 = 0.8125F; f = 0.3125F; f1 = 0.6875F; } else if (!flag && !flag1 && flag2 && flag3) { f4 = 0.8125F; f2 = 0.3125F; f3 = 0.6875F; } this.setBlockBounds (f, 0.0F, f2, f1, f4, f3); } } And here's the blockstates.json that I ended up using with it: { "forge_marker": 1, "variants": { "geometry": { "0": { "model": "wall_post" }, "4": { "model": "wall_n" }, "8": { "model": "wall_n", "y": 90, "uvlock": true }, "2": { "model": "wall_n", "y": 180, "uvlock": true }, "1": { "model": "wall_n", "y": 270, "uvlock": true }, "12": { "model": "wall_ne" }, "10": { "model": "wall_ne", "y": 90, "uvlock": true }, "3": { "model": "wall_ne", "y": 180, "uvlock": true }, "5": { "model": "wall_ne", "y": 270, "uvlock": true }, "6": { "model": "wall_ns" }, "9": { "model": "wall_ns", "y": 90, "uvlock": true }, "14": { "model": "wall_nse" }, "11": { "model": "wall_nse", "y": 90, "uvlock": true }, "7": { "model": "wall_nse", "y": 180, "uvlock": true }, "13": { "model": "wall_nse", "y": 270, "uvlock": true }, "15": { "model": "wall_nsew" }, "16": { "model": "wall_ns_above" }, "17": { "model": "wall_ns_above", "y": 90, "uvlock": true } }, "skin": { "0": { "textures": { "wall": "blocks/stonebrick" }}, "1": { "textures": { "wall": "blocks/stonebrick_mossy" }}, "2": { "textures": { "wall": "blocks/stonebrick_cracked" }}, "3": { "textures": { "wall": "blocks/stonebrick_carved" }}, "4": { "textures": { "wall": "blocks/brick" }}, "5": { "textures": { "wall": "blocks/hardened_clay" }}, "6": { "textures": { "wall": "blocks/netherrack" }}, "7": { "textures": { "wall": "blocks/quartz_block_chiseled" }}, "8": { "textures": { "wall": "blocks/obsidian" }}, "9": { "textures": { "wall": "blocks/sandstone_normal" }}, "10": { "textures": { "wall": "blocks/sandstone_carved" }}, "11": { "textures": { "wall": "blocks/stone" }}, "12": { "textures": { "wall": "blocks/stone_granite_smooth" }}, "13": { "textures": { "wall": "blocks/stone_diorite_smooth" }}, "14": { "textures": { "wall": "blocks/stone_andesite_smooth" }}, "15": { "textures": { "wall": "blocks/end_stone" }} } } } Notes: 1) The abstract wall class can be extended to as many sets of walls (16 each) as I want. I've taken to setting some custom hardness, blast resistance and light-values in each. 2) Because I have two whole sets of custom walls, I have another json file like this one (but with different textures). 3) This only put blocks in the world, not "items" (ItemBlock versions) in inventory. For the item blocks, I was forced to write 32 nearly identical json files for the models/item directory. Fortunately, each was able to declare both a texture and a vanilla parent, so I was able to avoid doing the 32 models/block files that vanilla code-monkeys did for their blocks. Here's an example of the models/item json for one ItemBlock: anystone_wall2.sealantern.json { "parent": "block/wall_inventory", "textures" : { "wall": "blocks/sea_lantern" }, "display": { "firstperson": { "rotation": [ 0, -135, 25 ], "translation": [ 0, 4, 2 ], "scale": [ 1.2, 1.2, 1.2 ] }, "thirdperson": { "rotation": [ 10, -45, 170 ], "translation": [ 0, 1.5, -2.75 ], "scale": [ 0.375, 0.375, 0.375 ] } } } The dot-subtype naming was my choice. I just had to make sure that I was consistent between file names and the result of my ItemBlock's getUnlocalizedName (ItemStack). I sincerely hope that Mojang (Microsoft) can find a code-monkey with more than half a brain to come up with an elegant way to specify that a particular item can use one default model for all of its variants, also allowing me to list the skins (textures) for all 16 in one file. Even better: As a default, MC could display an ItemBlock in inventory by rendering the block's default state at .375 scale. That one shortcut could eliminate hundreds of silly files and save modders hundreds of man-days of tedious effort.
  9. One tutorial (Wuppy Upgrading from 1.7 to 1. says that mc 1.8 items and blocks need to contain a static final variable called "name" and a public method called "getName". It doesn't say why, and it doesn't point to the part of Forge that needs these things (and reflection is really tricky to trace), so I'm somewhat unclear on what's really necessary. I've looked in the Forge docs, but I can't find answers to these questions. If someone knows (or could point me to the Forge class that uses name / getName() on items and/or blocks), I'd appreciate it. I'm trying to generalize some abstract classes for a whole series of mods, so I'd like to know what constraints I face. In particular: Is it enough to provide a getName method, or is the data member "name" also referenced via reflection? If so, does the class member need to be called exactly "name", all lowercase? Does "name" absolutely need to be final and/or static? I especially want to remove the "static" qualifier so my constructor can assign a value. How early does name need to get its value? Can I set it during construction? Do both items and blocks need these, or just one not the other? What are the consequences / symptoms of doing this wrong or not at all? I left out name and getName() from some of my ItemBlock classes, but I don't see any error messages. I tried setting a breakpoint on the getName() method and then debugging. I was able to load a world, place my blocks and save the world all without triggering on a call. Maybe reflection doesn't trigger breakpoints. Where does Forge call getName() or use name? If I could walk the source, I might answer my own questions. Maybe the name member and getName method are merely Wuppy's modding style needed to fit with his own private framework. If so, then I'd like to know so I can discard these apparently unused elements (and constraints).
  10. I currently have a similar problem, but it happens when I simply add a second mod to a world that had blocks placed by a first mod. The first mod's saved blocks appear as versions of blocks from the 2nd mod (the 2nd mod is "stealing" block IDs that should still be in use by the 1st). No I have three theories to test: 1) Forge has a bug (unlikely) 2) I am registering my blocks too soon. Some change in Forge between 1.7.10 and 1.8 may have delayed the acquisition of saved-game data beyond the pre-init phase. 3) I did something in the interim to change block name(s) so that Forge did not recognize the saved blocks as belonging to the 1st mod. I'm going to try to find where Forge attempts to reconcile saved blocks with incoming mods so I can see when it happens and by what means.
  11. I'm too lazy to setup multiple workspaces (and being somewhat paranoid, I like to keep copies of my work outside my workspace anyway), so I swap mods in and out of the Eclipse workspace at the drop of a hat. I have a separate file hierarchy where I keep each mod's gradle file, java files and resources (including mcmod.info). For convenience, that hierarchy also stores working jars, update logs, curse descriptions etc. When I want to swap mods, I move out what's changed and worth saving of one mod, delete the rest, and then copy in another. When swapping, I am operating on these four things: 1) build.gradle 2) mcmod.info 3) contents of resources/assets 4) contents of java It takes under a minute, and it prompts me to update and synchronize version text in the gradle and mcmod files. It's not as elegant as a working multi-mod setup, but it doubles as crude config management good enough for solo, hobby-level development.
  12. It's near impossible to scan several large java scripts and then notice what's *not* there. Have you set breakpoints in your custom renderer and then run the debugger? Have you searched the log for any registration or rendering errors? Start larding your code with temporary output statements to give yourself more info about what your program is really doing (it might not even be reaching your custom renderer for some reason). Then again, a simple minus sign could be rendering your entire painting bahind the surface of the block it's mounted on I did a paintings mod in 1.7, but it was over a year ago. I'll be upgrading it to 1.8 soon, so I'll be following this thread and have more to contribute when I get back into it.
  13. The Forge state loader seems to be working for the walls, but now I'm hung up on a multi-part blockstates file for my iron gate. The error message is "No base model or submodel provided for this MultiModel.Baked". I guess I don't understand the rules for the new json format. Here's my half baked (so to speak) blockstates json (which passes the json lint tool): { "forge_marker" : 1, "defaults" : { "textures" : { "texture" : "blocks/iron_block" } }, "variants" : { "context" : { "0" : { "model" : "block/fence_gate_closed" }, "1" : { "model" : "block/wall_gate_closed" }, "2" : { "model" : "block/fence_gate_open" }, "3" : { "model" : "block/wall_gate_open" } }, "facing" : { "south" : { }, "west" : { "y" : 90, "uvlock": true }, "north" : { "y" : 180, "uvlock": true }, "east" : { "y" : 270, "uvlock": true } } } } The "model" is determined by the value of the context property, and every possible value of context is covered, so I can't see why I'm being told that there's no model. What rule am I missing? Based on my (extremely) limited understanding of json format, I was expecting the loader to emit the Cartesian product of 4 models times 4 facings. Is it possible to separate those, or may I only separate textures from "variants"? Here's the full crash report: [11:08:09] [Client thread/INFO]: Created: 512x512 textures-atlas [11:08:10] [Client thread/INFO] [sTDOUT]: [net.minecraft.init.Bootstrap:printToSYSOUT:663]: ---- Minecraft Crash Report ---- // Daisy, daisy... Time: 8/25/15 11:08 AM Description: Initializing game java.lang.RuntimeException: No base model or submodel provided for this MultiModel.Baked. at net.minecraftforge.client.model.MultiModel$Baked.<init>(MultiModel.java:50) at net.minecraftforge.client.model.MultiModel.bake(MultiModel.java:196) at net.minecraftforge.client.model.ModelLoader$WeightedPartWrapper.bake(ModelLoader.java:393) at net.minecraftforge.client.model.ModelLoader$WeightedRandomModel.bake(ModelLoader.java:458) at net.minecraftforge.client.model.ModelLoader.setupModelRegistry(ModelLoader.java:122) at net.minecraft.client.resources.model.ModelManager.onResourceManagerReload(ModelManager.java:29) at net.minecraft.client.resources.SimpleReloadableResourceManager.registerReloadListener(SimpleReloadableResourceManager.java:130) at net.minecraft.client.Minecraft.startGame(Minecraft.java:511) at net.minecraft.client.Minecraft.run(Minecraft.java:356) at net.minecraft.client.main.Main.main(Main.java:117) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) at net.minecraft.launchwrapper.Launch.main(Launch.java:28) A detailed walkthrough of the error, its code path and all known details is as follows: --------------------------------------------------------------------------------------- -- Head -- Stacktrace: at net.minecraftforge.client.model.MultiModel$Baked.<init>(MultiModel.java:50) at net.minecraftforge.client.model.MultiModel.bake(MultiModel.java:196) at net.minecraftforge.client.model.ModelLoader$WeightedPartWrapper.bake(ModelLoader.java:393) at net.minecraftforge.client.model.ModelLoader$WeightedRandomModel.bake(ModelLoader.java:458) at net.minecraftforge.client.model.ModelLoader.setupModelRegistry(ModelLoader.java:122) at net.minecraft.client.resources.model.ModelManager.onResourceManagerReload(ModelManager.java:29) at net.minecraft.client.resources.SimpleReloadableResourceManager.registerReloadListener(SimpleReloadableResourceManager.java:130) at net.minecraft.client.Minecraft.startGame(Minecraft.java:511) -- Initialization -- Details: Stacktrace: at net.minecraft.client.Minecraft.run(Minecraft.java:356) at net.minecraft.client.main.Main.main(Main.java:117) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) at net.minecraft.launchwrapper.Launch.main(Launch.java:28) -- System Details -- Details: Minecraft Version: 1.8 Operating System: Windows XP (x86) version 5.1 Java Version: 1.7.0_55, Oracle Corporation Java VM Version: Java HotSpot(TM) Client VM (mixed mode, sharing), Oracle Corporation Memory: 79954512 bytes (76 MB) / 193601536 bytes (184 MB) up to 259522560 bytes (247 MB) JVM Flags: 0 total; IntCache: cache: 0, tcache: 0, allocated: 0, tallocated: 0 FML: MCP v9.10 FML v8.0.99.99 Minecraft Forge 11.14.3.1450 4 mods loaded, 4 mods active States: 'U' = Unloaded 'L' = Loaded 'C' = Constructed 'H' = Pre-initialized 'I' = Initialized 'J' = Post-initialized 'A' = Available 'D' = Disabled 'E' = Errored UCH mcp{9.05} [Minecraft Coder Pack] (minecraft.jar) UCH FML{8.0.99.99} [Forge Mod Loader] (forgeSrc-1.8-11.14.3.1450.jar) UCH Forge{11.14.3.1450} [Minecraft Forge] (forgeSrc-1.8-11.14.3.1450.jar) UCH jrfwalls{v1.7.10-00.01.05 Beta} [uncle Jeff's Walls Mod] (bin) Loaded coremods (and transformers): GL info: ' Vendor: 'ATI Technologies Inc.' Version: '3.2.9232' Renderer: 'ATI Radeon HD 3200 Graphics' Launched Version: 1.6 LWJGL: 2.9.1 OpenGL: ATI Radeon HD 3200 Graphics GL version 3.2.9232, ATI Technologies Inc. GL Caps: Using GL 1.3 multitexturing. Using GL 1.3 texture combiners. Using framebuffer objects because OpenGL 3.0 is supported and separate blending is supported. Shaders are available because OpenGL 2.1 is supported. VBOs are available because OpenGL 1.5 is supported. Using VBOs: No Is Modded: Definitely; Client brand changed to 'fml,forge' Type: Client (map_client.txt) Resource Packs: [] Current Language: English (US) Profiler Position: N/A (disabled) [11:08:10] [Client thread/INFO] [sTDOUT]: [net.minecraft.init.Bootstrap:printToSYSOUT:663]: #@!@# Game crashed! Crash report saved to: #@!@# D:\Projects\Minecraft\Forge1450\.\crash-reports\crash-2015-08-25_11.08.10-client.txt UPDATE: Solved the latest problem -- "block/" is for textures, not models. I removed "block/" from in front of my model names and the problem went away (D'oh!). I'm in the home stretch now...
  14. Fair enough; I can copy-paste all 32 wall geometries. I'm just happy that I don't need to multiply that by all 15 (and counting) skins!
  15. Regarding Forge blockstates: Can I nest properties? Can the effect of one property value be another property with a set of values? In my case, I have two values of one property that then look at another property for a true/false before choosing a model. I'm giving it a try, but I might not intuit the syntax correctly: "geometry": { "0": { "model": "wall_post" }, "4": { "model": "wall_n" }, "8": { "model": "wall_n", "y": 90, "uvlock": true }, "2": { "model": "wall_n", "y": 180, "uvlock": true }, "1": { "model": "wall_n", "y": 270, "uvlock": true }, "12": { "model": "wall_ne" }, "10": { "model": "wall_ne", "y": 90, "uvlock": true }, "3": { "model": "wall_ne", "y": 180, "uvlock": true }, "5": { "model": "wall_ne", "y": 270, "uvlock": true }, "6": { "up": { "true": { "model": "wall_ns" }, "false": { "model": "wall_ns_above" } } }, "9": { "up": { "true": { "model": "wall_ns", "y": 90, "uvlock": true }, "false": { "model": "wall_ns_above", "y": 90, "uvlock": true } } }, "14": { "model": "wall_nse" }, "11": { "model": "wall_nse", "y": 90, "uvlock": true }, "7": { "model": "wall_nse", "y": 180, "uvlock": true }, "13": { "model": "wall_nse", "y": 270, "uvlock": true }, "15": { "model": "wall_nsew" }, } }
  16. From the doc: Instead of defining “this combination of properties gives model X” we say “this value for this property has THAT impact on the model”. That's EXACTLY the mindset I have for my mod! Note to tutorial writers: Mention both json structures, and include Lex's link to the doc. I expect success shortly, whereupon I'll add SOLVED to the OP subject line.
  17. In a json file (blockstates), must each listed state be complete (i.e. provide a value for each and every property)? Is there a wildcard like "any" that would allow me to write one line to take the place of many (where one property has no effect in this list)? What I am trying to do is to separate my block's geometry from its skin (texture). I want to use some of the block's properties to control what model to use, and I want to use a separate property to choose texture. Because there are 32 geometries and 15 textures, I desperately want to avoid having to list the complete 480-line Cartesian product of all those models and textures. What I have in mind is something along these lines for my blockstates file (an extension of BlockWall: { "textures": { "skin=0": { "texture": "blocks/stonebrick" }, "skin=1": { "texture": "blocks/stonebrick_mossy" }, "skin=2": { "texture": "blocks/stonebrick_cracked" }, "skin=3": { "texture": "blocks/stonebrick_carved" }, "skin=4": { "texture": "blocks/brick" }, "skin=5": { "texture": "blocks/hardened_clay" }, "skin=6": { "texture": "blocks/netherrack" }, "skin=7": { "texture": "blocks/quartz_block_chiseled" }, "skin=8": { "texture": "blocks/obsidian" }, "skin=9": { "texture": "blocks/sandstone_normal" }, "skin=10": { "texture": "blocks/sandstone_carved" }, "skin=11": { "texture": "blocks/stone" }, "skin=12": { "texture": "blocks/stone_andesite_smooth" }, "skin=13": { "texture": "blocks/stone_diorite_smooth" }, "skin=14": { "texture": "blocks/stone_granite_smooth" } } "variants": { "east=false,north=false,south=false,up=false,west=false": { "model": "wall_post" }, "east=false,north=false,south=false,up=true,west=false": { "model": "wall_post" }, "east=false,north=true,south=false,up=false,west=false": { "model": "wall_n" }, "east=true,north=false,south=false,up=false,west=false": { "model": "wall_n", "y": 90, "uvlock": true }, "east=false,north=false,south=true,up=false,west=false": { "model": "wall_n", "y": 180, "uvlock": true }, "east=false,north=false,south=false,up=false,west=true": { "model": "wall_n", "y": 270, "uvlock": true }, "east=false,north=true,south=false,up=true,west=false": { "model": "wall_n" }, "east=true,north=false,south=false,up=true,west=false": { "model": "wall_n", "y": 90, "uvlock": true }, "east=false,north=false,south=true,up=true,west=false": { "model": "wall_n", "y": 180, "uvlock": true }, "east=false,north=false,south=false,up=true,west=true": { "model": "wall_n", "y": 270, "uvlock": true }, "east=true,north=true,south=false,up=false,west=false": { "model": "wall_ne" }, "east=true,north=false,south=true,up=false,west=false": { "model": "wall_ne", "y": 90, "uvlock": true }, "east=false,north=false,south=true,up=false,west=true": { "model": "wall_ne", "y": 180, "uvlock": true }, "east=false,north=true,south=false,up=false,west=true": { "model": "wall_ne", "y": 270, "uvlock": true }, "east=true,north=true,south=false,up=true,west=false": { "model": "wall_ne" }, "east=true,north=false,south=true,up=true,west=false": { "model": "wall_ne", "y": 90, "uvlock": true }, "east=false,north=false,south=true,up=true,west=true": { "model": "wall_ne", "y": 180, "uvlock": true }, "east=false,north=true,south=false,up=true,west=true": { "model": "wall_ne", "y": 270, "uvlock": true }, "east=false,north=true,south=true,up=false,west=false": { "model": "wall_ns" }, "east=true,north=false,south=false,up=false,west=true": { "model": "wall_ns", "y": 90, "uvlock": true }, "east=false,north=true,south=true,up=true,west=false": { "model": "wall_ns_above" }, "east=true,north=false,south=false,up=true,west=true": { "model": "wall_ns_above", "y": 90, "uvlock": true }, "east=true,north=true,south=true,up=false,west=false": { "model": "wall_nse" }, "east=true,north=false,south=true,up=false,west=true": { "model": "wall_nse", "y": 90, "uvlock": true }, "east=false,north=true,south=true,up=false,west=true": { "model": "wall_nse", "y": 180, "uvlock": true }, "east=true,north=true,south=false,up=false,west=true": { "model": "wall_nse", "y": 270, "uvlock": true }, "east=true,north=true,south=true,up=true,west=false": { "model": "wall_nse" }, "east=true,north=false,south=true,up=true,west=true": { "model": "wall_nse", "y": 90, "uvlock": true }, "east=false,north=true,south=true,up=true,west=true": { "model": "wall_nse", "y": 180, "uvlock": true }, "east=true,north=true,south=false,up=true,west=true": { "model": "wall_nse", "y": 270, "uvlock": true }, "east=true,north=true,south=true,up=false,west=true": { "model": "wall_nsew" }, "east=true,north=true,south=true,up=true,west=true": { "model": "wall_nsew" } } } Sadly, looking at how vanilla created a full brace of models for each type of wall (mossy and cobble), with each model simply repeating the texture in its own name, I am pessimistic for my chances to do something more elegant. If there's no way to treat independent properties separately, then I'll end up with 15 nearly identical blockstates files and 85 model files, every one of them prone to typing errors It's so ugly that the artist in me has to try to do better. BTW, Does anyone know where the json files get processed? If I could lay eyes on the source code, then I might answer my own question (or make an improvement). Update: By having the debugger blow up on launch, I've found a Forge block properties loader with an interesting bit of Forge magic switching on a "marker" to a custom branch of json loading that I don't yet understand. I'm hoping that what I want to do is or can be supported in there. If property wildcards are not yet supported, then perhaps I should write a wish-list request (either wildcards or something like "intake multiple, disjoint sets and perform the Cartesian product on the fly") in a different subforum. Where may I read up on the features of Forge's enhanced json loader (and how do I set the marker)? Are wildcard property values supported? How about bracketed value-lists? Could an enhanced loader read in a texture list plus a model list and perform a Cartesian product in software? Can you tell that I miss mc1.7.10 where all I had to do was extend class BlockWall and override the texture function to use metadata? UPDATE: Workaround: Forge has a custom json format that can at least break the Cartesian product into tolerable independent variables. See discussion below.
  18. Where's the main class? Is anything actually calling proxy.preinit(...) so that the registration happens? As usual for such threads, I recommend setting a break point ahead of the crash (and maybe ahead of your entire mod's construction) and re-running in the debugger so you can walk through everything you *think* it is doing. When your program does something unexpected (or skips something critical), it's usually painfully obvious and easy to fix.
  19. IIRC, Like flowers, reeds are planted as themselves, not as seeds. Since your corn is a seeded plant, then crop might be a better parent (do more for you). While a print statement may be informative, I'd recommend setting a breakpoint and stepping through the constructor using the debugger. The reason to use the debugger is to get over any aversion / sense of mystery you might feel toward using that tool. Once you've added the "debugger" arrow to your quiver, you'll become a much more powerful code warrior. Problems like this can be solved in a handful of minutes when you can respond to a crash by launching the debugger, running up to the edge of the crash, and examining every variable within reach before stepping into the call that failed. Therefore, force yourself to climb its learning curve, become familiar with it, and then it will become easy-peasy (and powerful).
  20. When you "go to Minecraft", are you starting a new world, or are you entering an existing one? Generation only occurs when you visit a virgin chunk. Previously generated chunks will not be changed by new mods with new ore generators.
  21. How can the 2nd method even return zero? It's return "type" is void, so assigning it to an L-value should earn you a warning from Eclipse.
  22. I looked through your code again, and I'm not spotting any drop-dead differences between the metals and the gems. You might want to set a debug breakpoint on your generateOre call to one of those gem ores. The only thing I can think of: Your height ranges are high, so a lot of the gem ores will fail when they try to generate in air (and even above the height limit for the Overworld). Maybe you just didn't get many and couldn't find them. Do a test where they're confined to a narrow range with lots of rock. See if they become easier to find. If so, then you just need to calibrate your numbers to get the scarcity and distribution you want. Oh, and when testing world generators, you need to start a new world (or go to previously unvisited chunks) to spawn new generation every time. Otherwise you see only what was generated (or failed) when the world/chunk spawned sometime in the past.
  23. Because you misspelled the method name, inadvertently creating a new method instead of overriding the one that will be called by the game. Correcting spelling and parameter mismatches (and keeping up with superclass edits) is why we add the annotation wherever applicable. As it turns out, the default method in BlockOre will drop one for anything other than lapis, so your method is actually unnecessary (not hurting, just taking up space).
  24. Okay, time to show some source code. Here's my extension of the Enchantment interface: package jrfnethergem; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.init.Items; import net.minecraft.item.ItemHoe; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.util.EnumHelper; public class classSmartHarvestEnchantment extends Enchantment { public static final EnumEnchantmentType enchantType = EnumHelper.addEnchantmentType ("farmer"); private static final int SMART_HARVEST_ID = enchantType.ordinal (); protected static ResourceLocation resourceLoc = new ResourceLocation ("SmartHarvest"); public classSmartHarvestEnchantment() { super (SMART_HARVEST_ID, resourceLoc, 11, enchantType); // Assigns effectId, weight & type; adds to list/map this.setName ("smartHarvest"); this.addToBookList (this); } /* * The minimal value of enchantability needed on the enchantment level passed. */ public int getMinEnchantability(int level) { return 11; } /* * The maximum value of enchantability allowed on the enchantment level passed. It is meant only to shift toward high-levels for * enchantments that have multiple levels. SmartHarvest has only one level (1), so this is irrelevant. This function has no effect * on the chance for multiple enchantments. */ public int getMaxEnchantability(int level) { return 50; } @Override public boolean canApply(ItemStack s) { // Applies only to hoes return (s.getItem () instanceof ItemHoe); } }
  25. My first suspicion would be that you got some part of common code into a client-side only class. Therefore, what I would want to see is *where* your mod code resides (or what it overrides). Be especially suspicious of any existential code sharing a location with rendering / texturing. Only the client needs to worry about drawing pictures, but both server *and* client need to know existence, position etc. Oh, another thing: The goat may exist in both your client and server, but the problem could be with your friend's installation of your mod (or a conflicting mod). You should do some careful debugging/logging of goat spawning on all three to see where the ball is actually being dropped.
×
×
  • Create New...

Important Information

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