-
Content Count
374 -
Joined
-
Last visited
Content Type
Profiles
Forums
Calendar
Posts posted by IceMetalPunk
-
-
The only thing I can think of is code that references the world folder. Because the world folder is on the dedicated server when there is one, any code that references it should probably be in the server proxy. But honestly, I'm just speculating and haven't tried any such code, so it might work in the common proxy as well.
-
11 minutes ago, funsize888 said:So I could do something like:
Black block = world.getBlock();
if(block = Blocks.TALLGRASS){
block.isReplaceable();
I know this isn't exact but I don't have my computer in front of me right now
No. isReplaceable() is not a setter, it's a getter. Meaning when you call it, it is returning true or false, meaning whether or not the block is replaceable. It does not set that. You should be checking the value of isReplaceable() to determine if the block is, in fact, replaceable, and if so, using other methods (such as World#setBlockState or something) to replace it.
-
Posted · Edited by IceMetalPunk
Added Solved Tag
I'm just trying to get a sound to play, but it's not. It's not playing anything, but there are no errors or warnings logged. For the filenames below, my mod ID is redplusplus.
I have a sounds.json file in my assets/redplusplus folder with this in it:{ "redplusplus:item.redstone_sandwich.eat": { "sounds": [ "redplusplus:item/redstone_sandwich/eat" ] } }
I've also tried leaving out the redplusplus domain from the sound location, but it didn't help. (And of course, if I leave the redplusplus domain out of the sound name itself, I get an "unable to play empty sound" error, so I think it's necessary, yes?)
I have a class which extends SoundEvent for easier registration, which just sets the registry name upon initialization:package com.icemetalpunk.redplusplus.sounds; import com.icemetalpunk.redplusplus.RedPlusPlus; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraftforge.fml.common.registry.GameRegistry; public abstract class RedPlusPlusSound extends SoundEvent { public RedPlusPlusSound(String name) { super(new ResourceLocation(RedPlusPlus.MODID, name)); this.setRegistryName(new ResourceLocation(RedPlusPlus.MODID, name)); } public void register() { GameRegistry.findRegistry(SoundEvent.class).register(this); } }
And then my sound group classes extend RedPlusPlusSound, taking in a specific name within the group; for instance, I have this class for the sounds related to eating "redstone sandwiches" (an item in my mod):
package com.icemetalpunk.redplusplus.sounds; public class SoundRedstoneSandwich extends RedPlusPlusSound { public SoundRedstoneSandwich(String subset) { super("item.redstone_sandwich." + subset); } }
So I can have item.redstone_sandwich.eat, and in the future (when this is working), item.redstone_sandwich.super, etc. all be instances of the same class.
And then I actually just call these instances' register() methods (defined in the parent RedPlusPlusSound class above) in a handler for the RegistryEvent<SoundEvent> event type.
I do have the file assets/redplusplus/sounds/item/redstone_sandwich/eat.ogg which is a non-empty sound. And when I use the /playsound command, that full resource location for my sound does properly auto-complete, so it's definitely registering something with that name.So what would cause the sound not to play if there's no indication of any errors?
-
Posted · Edited by IceMetalPunk
Added quote
2 minutes ago, Draco18s said:Yes. Json files is the 1.12 way.
I wonder if this is the cause of my previous crashing problem I asked about in another topic that was never answered. If I were to have a recipe in its .json form and also register it through addShapedRecipe / addShapelessRecipe, would that cause a conflict and crash? (The error message received is a generic JVM one, so I didn't know where the problem was other than it only happened when I added the advancement and recipe .json files.)
-
Can you actually register recipes from the JSON files? I've been using GameRegistry.addShapedRecipe / GameRegistry.addShapelessRecipe in 1.12, and it works just fine...
-
Posted · Edited by IceMetalPunk
Typo fixing
Since 1.12 is encouraging recipes to be unlocked, I figured I'd make my mod's recipes unlockable in the same way. So as a quick test, I started with just one. I created the assets/redplusplus/advancements/recipes folder and basically copied/pasted one of the vanilla recipe advancements in. Then I changed it to trigger when getting a comparator in your inventory instead of the iron ingot that was there, and to unlock my redplusplus:block_redstone_counter recipe instead of the one it was unlocking. (I also made a copy of the vanilla recipes/root.json advancement, which is just an impossible trigger and nothing else, and parented my advancement to that one just in case.)
Then I created the assets/redplusplus/recipes/block_redstone_counter.json file, where I copied the recipe file for an anvil and changed the recipe ingredients and output. The ingredients are all vanilla items, the output is my custom item.I made sure to use the proper domains for all resource locations in these files, whether they're minecraft: or redplusplus: alike.
The game loads fine, but when I open a crafting table, it crashes completely. The weird thing is the stacktrace doesn't include any of my code, only vanilla code; can someone help me pinpoint what I've done to cause a fatal error here?
Stacktrace:[main/FATAL]: Error executing task java.util.concurrent.ExecutionException: java.lang.IndexOutOfBoundsException: bitIndex < 0: -1 at java.util.concurrent.FutureTask.report(Unknown Source) ~[?:1.8.0_111] at java.util.concurrent.FutureTask.get(Unknown Source) ~[?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:54) [Util.class:?] at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1161) [Minecraft.class:?] at net.minecraft.client.Minecraft.run(Minecraft.java:436) [Minecraft.class:?] at net.minecraft.client.main.Main.main(Main.java:118) [Main.class:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_111] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_111] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_111] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_111] at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?] at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_111] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_111] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_111] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_111] at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) [start/:?] at GradleStart.main(GradleStart.java:26) [start/:?] Caused by: java.lang.IndexOutOfBoundsException: bitIndex < 0: -1 at java.util.BitSet.get(Unknown Source) ~[?:1.8.0_111] at net.minecraft.stats.RecipeBook.containsRecipe(RecipeBook.java:35) ~[RecipeBook.class:?] at net.minecraft.client.gui.recipebook.RecipeList.func_194214_a(RecipeList.java:35) ~[RecipeList.class:?] at net.minecraft.client.network.NetHandlerPlayClient.lambda$handleRecipeBook$2(NetHandlerPlayClient.java:1636) ~[NetHandlerPlayClient.class:?] at java.util.ArrayList.forEach(Unknown Source) ~[?:1.8.0_111] at net.minecraft.client.network.NetHandlerPlayClient.handleRecipeBook(NetHandlerPlayClient.java:1634) ~[NetHandlerPlayClient.class:?] at net.minecraft.network.play.server.SPacketRecipeBook.processPacket(SPacketRecipeBook.java:40) ~[SPacketRecipeBook.class:?] at net.minecraft.network.play.server.SPacketRecipeBook.processPacket(SPacketRecipeBook.java:14) ~[SPacketRecipeBook.class:?] at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:21) ~[PacketThreadUtil$1.class:?] at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:1.8.0_111] at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:53) ~[Util.class:?] ... 15 more
-
Ah, I didn't even look at the date! >_< I may switch over to the newest release, then, at some point. For now, I'll make sure the rest of my mod is functional and then transition after.
Thanks for the help!
-
Ah. I could swear I tried registering a block with the same name as a Minecraft block (and domain), and got an error for trying to register duplicate entries. Then again, I haven't been using the registry events, and have been registering things in the preInit, so I'll try to switch over to the events and see if I can get it working after all.
Thank you! -
Posted · Edited by IceMetalPunk
Added question.
Hm. That's annoying. I'm trying to make my mod as vanilla-feeling as possible, and having a special machine for just one recipe (or a small handful) puts it in the mod-feel realm.
Thanks for the info; I'll see if there's some hacky workaround I can come up with, or else just scrap the feature I was planning.*EDIT* Speaking of workarounds, it seems substitution aliases no longer exist. What would be the proper way to replace the vanilla furnace block with a custom one that implements my custom recipes? Because that may work, if it can be done.
-
Is there a way to register a smelting recipe that requires a certain fuel item? For instance, a recipe that only works if you smelt the item with coal, but not if you smelt it with wood or lava? Since the GameRegistry.addSmelting methods don't have options for that, I thought I'd need to use event handling, but while there are events for pre-and-post brewing, I can't find any for smelting.
So how would I do this? -
Posted · Edited by IceMetalPunk
Solved it myself
I'm trying to make a simple analog lamp, where the light output equals the max redstone input. I thought this would be simple, but it's not working. This is the relevant code, inside the block class:
@Override public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos) { if (world instanceof World) { World theWorld = (World) world; return theWorld.isBlockIndirectlyGettingPowered(pos); } return 0; } @Override public void observedNeighborChange(IBlockState thisState, World world, BlockPos thisPos, Block changedBlock, BlockPos changedBlockPos) { world.setLightFor(EnumSkyBlock.BLOCK, thisPos, world.isBlockIndirectlyGettingPowered(thisPos)); world.checkLight(thisPos); }
Some debug output shows that the observedNeighborChange() method is being called correctly, when there's a block state change next to the lamp, and that isBlockIndirectlyGettingPowered() is returning the appropriate redstone signal strength.
Yet the block never lights up. Why not?*Update* After more testing, it seems like the block light *is* getting set properly, but only after I exit the world and reload it. I thought checkLight() was supposed to update the light levels; if it's not, what do I need to call to update the light levels without relogging?
*UPDATE 2* I fixed it! As it turns out, you need to change the block state for Minecraft to actually update the lighting. Even calling setBlockState with the current state won't work; it needs to be a new block state. So I added a "power" property and set power equal to the redstone input, then I change the blockstate whenever the neighbor changes and it all works fine. -
2 minutes ago, Draco18s said:ModelLoader needs to be called during PreInit, not Init.
Ah! And now it works!
So what's the main benefit to using ModelLoader rather than ItemModelMesher? They seem to work equally well, just with registration occurring at different times. Is there a benefit under the hood I'm not aware of?
-
2 minutes ago, Draco18s said:Why are you using the ModelMesher?
If you're going to do it this way (and not the Registry events) then you should be using ModelLoader.setCustomModelResourceLocation
Dylem's solution seems to work just fine; when I tried switching the code to ModelLoader.setCustomModelResourceLocation(this.itemBlock, 0, model) [this.itemBlock is of course the ItemBlock instance], it doesn't work, it just shows the purple-and-black undefined model instead again...
-
-
That helps, but what is the ItemModelMesher instance passed as an argument? I assume I can't just create a new instance of it and use that; where does it come from?
-
Posted · Edited by IceMetalPunk
Solved
I've added a new block to the game, which is fully functional. It has its own block model and textures, which also works fine. But now, I'm trying to give its ItemBlock a model, and it's just not working.
I've noticed that quite a few things about item and block registration have changed in Forge for 1.12; how would I properly register an item model?
Currently, I'm simply creating an ItemBlock from my block class and registering it with the GameRegistry.findRegistry(Item.class) registry. Then I have a JSON file in my assets/<mod>/models/item folder (using the actual mod ID, not literally "<mod>") which simply defines the model parent to be the block model that already works.
But the item isn't showing up; it's just the standard purple-and-black "not found" texture instead. So then I tried adding a call, after registering the item with FML, to ModelBakery.registerItemVariants passing only one registry name to it, in hopes that would work out; it didn't change anything. No errors, just also no item model.
I'm probably missing a step or two; what am I missing? -
10 minutes ago, Choonster said:It's best to include the pack.mcmeta file so you're using the current resource pack format with lowercase names.
LegacyV2Adapter is only meant for loading resource packs designed for previous versions of Minecraft and could be removed at some point in the future, so it's best not to rely on it.
That's what I figured. Thanks for all your help!
-
13 minutes ago, Choonster said:Do you have a pack.mcmeta file in src/main/resources with pack_format set to 3?
If you don't, Forge will load your mod's resources using the LegacyV2Adapter IResourcePack wrapper. This means that your lang files will be loaded with the old mixed-case names (e.g. en_US.lang) rather than the new lower-case names (e.g. en_us.lang).
If you do, your lang files should be loaded with lower-case names. Try refreshing your IDE project (i.e. click the "Refresh all Gradle projects" button in IDEA's Gradle window or re-run the eclipse Gradle task) and/or rebuilding it.
Well. I had no idea that a pack.mcmeta file was required for mod resources to prevent it from loading legacy filenames. I added that, and lo and behold, it works now
Thank you! I learn something new everyday. A question about convention, though: is it better to include the pack.mcmeta file, or to leave it out and use the old mixed-case filenames instead? I'd assume using the new lower-case names with the pack file is preferred, but I'd like to be sure. -
It's been awhile since the last time I've worked on any mods, so I'm probably overlooking something stupid here, but I can't seem to figure out the problem; so here I am.
The issue is simple: my language file isn't loading properly. None of the strings (or at least, the creative tab name and the item name for the one block I've added) are translating.
Here's a screenshot to show you:I create the tab like this, for reference of the tab name:
public static CreativeTabs tab = new CreativeTabs("warpstone") { @Override public ItemStack getTabIconItem() { return new ItemStack(Item.getItemFromBlock(Warpstone.blocks.get("warpstone_ore"))); } };
I set the unlocalized name of the block *and* ItemBlock to "warpstone_ore".
And in my mod's src folder, I have the file
main\resources\assets\warpstone\lang\en_us.lang
With these basic contents:
tile.warpstone_ore.name=Warpstone Ore itemGroup.warpstone=Warpstone
And yet, as you can see from the screenshot, it's definitely not translating the names at all. What am I doing wrong?
-
When you save the
NBTTagCompound
inside the
ItemStack
, you also save the coordinates of the
Block
at the location it was broken at. Then, when you place it down, you read from the
ItemStack
's
NBTTagCompound
, thus also setting the position of the
TileEntity
to the coordinates of the previous location. This may be why it's not getting ticked.
Setting the correct position after reading from NBT should fix this issue, if this is what caused it.
That worked! And it makes sense, too! Thank you!
(Also, an interesting note: if the position tags are wrong, and I run the /blockdata command on the block's position, it seems to automatically fix the position in the tile entity tags [showing a successful change to the tags even if I supply an empty tag to the command] and the updates start ticking again. Weird, but interesting.)
You don't need to read the data into the TE manually. Minecraft already does that for the BlockEntityTag tag on ItemBlocks.
And yet if I don't load it myself in that onBlockPlacedBy override, when I re-place a broken block, all the tile entity data is lost completely (I just tested it)...
-
The TileEntity cannot be accessed in
getDrops
, it is called after the Block has already been removed from the World. See the patches forge makes to
BlockFlowerPot
(between FORGE START and FORGE END).
Thank you! It's a bit silly to check what the block should drop after its associated data is already removed, isn't it? But anyway, overriding the removedByPlayer and harvestBlock methods appropriately did the trick, and now it's dropping! It's almost working, except... when I place the block back down, it correctly retains the tile entity data, but it seems as though the tile entity stops ticking/updating. No errors, it just never runs the update code (and yet, the constructor is being called, so the TE is created, just not ticking).
Here's the entire TE class, block base class, and specific block class I'm testing with:
Tile Entity:
package com.icemetalpunk.chaotica.tileentities; import java.util.Iterator; import java.util.Map; import javax.annotation.Nullable; import com.icemetalpunk.chaotica.Chaotica; import com.icemetalpunk.chaotica.ChaoticaUtils; import com.icemetalpunk.chaotica.fluids.FluidTankChaos; import com.icemetalpunk.chaotica.handlers.ChaoticaMessage; import com.icemetalpunk.chaotica.handlers.ChaoticaPacketHandler; import com.icemetalpunk.chaotica.sounds.ChaoticaSoundRegistry; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.SoundCategory; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; public class TileEntityChaoticCondenser extends ChaoticaTEBase implements ICapabilityProvider, ITickable { protected Fluid fluid = Chaotica.fluids.CORROSIVE_CHAOS; protected int capacity = 5 * Fluid.BUCKET_VOLUME; protected FluidTankChaos tank = new FluidTankChaos(this.capacity); protected int countdown = 40; protected int maxCountdown = 60; // Max amount it resets to public TileEntityChaoticCondenser() { this.tank.setTileEntity(this); System.out.println("Created TE"); } @Override public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) { if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { return true; } return super.hasCapability(capability, facing); } @Override public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) { if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(this.tank); } return super.getCapability(capability, facing); } // Ticks until the next check for blocks to convert to chaos public int getCountdown() { return this.countdown; } public int getMaxCountdown() { return this.maxCountdown; } public Fluid getFluid() { if (tank.getFluid() == null) { return null; } return this.tank.getFluid().getFluid(); } public void setFluidAmount(int amount) { if (tank.getFluid() == null) { tank.setFluid(new FluidStack(this.fluid, 0)); } tank.getFluid().amount = amount; } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); NBTTagCompound tankTag = tag.getCompoundTag("Tank"); this.tank.readFromNBT(tankTag); this.countdown = tag.getInteger("Countdown"); } @Override public NBTTagCompound writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); NBTTagCompound tankTag = new NBTTagCompound(); tank.writeToNBT(tankTag); tag.setTag("Tank", tankTag); tag.setInteger("Countdown", this.countdown); return tag; } public int fill(int amount, boolean doFill) { return this.tank.fill(new FluidStack(this.fluid, amount), doFill); } @Override public void update() { System.out.println("Updating TE"); if (--this.countdown == 0) { this.countdown = this.maxCountdown; if (!this.worldObj.isRemote) { IBlockState east = this.getWorld().getBlockState(this.pos.east()); IBlockState west = this.getWorld().getBlockState(this.pos.west()); IBlockState north = this.getWorld().getBlockState(this.pos.north()); IBlockState south = this.getWorld().getBlockState(this.pos.south()); IBlockState up = this.getWorld().getBlockState(this.pos.up()); IBlockState down = this.getWorld().getBlockState(this.pos.down()); // Iterate over the amounts map and add the appropriate amount // of fluid if applicable boolean playSound = false; Iterator<Map.Entry<ChaoticaUtils.BlockPair, Integer>> it = ChaoticaUtils.pairAmounts.entrySet().iterator(); while (it.hasNext()) { Map.Entry<ChaoticaUtils.BlockPair, Integer> entry = it.next(); ChaoticaUtils.BlockPair pair = entry.getKey(); int amount = entry.getValue().intValue(); if (pair.isPair(east.getBlock(), west.getBlock())) { if (this.fill(amount, true) > 0) { playSound = true; this.getWorld().destroyBlock(this.pos.east(), false); this.getWorld().destroyBlock(this.pos.west(), false); } } if (pair.isPair(north.getBlock(), south.getBlock())) { if (this.fill(amount, true) > 0) { playSound = true; this.getWorld().destroyBlock(this.pos.north(), false); this.getWorld().destroyBlock(this.pos.south(), false); } } if (pair.isPair(up.getBlock(), down.getBlock())) { if (this.fill(amount, true) > 0) { playSound = true; this.getWorld().destroyBlock(this.pos.up(), false); this.getWorld().destroyBlock(this.pos.down(), false); } } } if (playSound) { this.worldObj.playSound(null, this.getPos(), ChaoticaSoundRegistry.CONDENSE_CHAOS, SoundCategory.BLOCKS, 1.0f, 1.0f); ChaoticaPacketHandler.INSTANCE.sendToAll(new ChaoticaMessage(ChaoticaMessage.MessageTypes.CONDENSER_LEVEL, this.pos.getX(), this.pos.getY(), this.pos.getZ(), this.tank.getFluidAmount())); } } } } // If shouldHarvest() returns true, this will drop a fully tagged item // instead of an empty one. @Override public boolean shouldHarvest() { return true; } @Override public ItemStack getHarvest() { Block block = this.worldObj.getBlockState(this.pos).getBlock(); Item item = Item.getItemFromBlock(block); ItemStack stack = new ItemStack(item, 1); NBTTagCompound nbt = new NBTTagCompound(); this.writeToNBT(nbt); stack.setTagCompound(nbt); return stack; } }
TE Provider Block Base Class:
package com.icemetalpunk.chaotica.blocks; import java.util.ArrayList; import com.google.common.collect.Lists; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; public abstract class ChaoticaTEBlock extends ChaoticaBlockBase { public ChaoticaTEBlock(String name, Material materialIn) { super(name, materialIn); } // Make sure when the block is dropped, the item retains the TE's data tags @Override public final ArrayList<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { int meta = state.getBlock().getMetaFromState(state); ItemStack ret = new ItemStack(this, 1, meta); NBTTagCompound nbt = new NBTTagCompound(); TileEntity te = world.getTileEntity(pos); NBTTagCompound teTag = new NBTTagCompound(); te.writeToNBT(teTag); nbt.setTag("BlockEntityTag", teTag); ret.setTagCompound(nbt); return Lists.newArrayList(ret); } @Override public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { if (willHarvest) return true; // If it will harvest, delay deletion of // the block until after getDrops return super.removedByPlayer(state, world, pos, player, willHarvest); } @Override public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, TileEntity te, ItemStack tool) { super.harvestBlock(world, player, pos, state, te, tool); world.setBlockToAir(pos); } @Override public boolean canHarvestBlock(IBlockAccess world, BlockPos pos, EntityPlayer player) { return true; } // When placed, if the item has a tag, set the tile entity's tag /* * FIXME: When placed like this, tags are properly set, but tile entity * fails to update ever after. */ @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { super.onBlockPlacedBy(worldIn, pos, state, placer, stack); if (stack.hasTagCompound() && stack.getTagCompound().hasKey("BlockEntityTag")) { NBTTagCompound tag = stack.getTagCompound().getCompoundTag("BlockEntityTag"); worldIn.getTileEntity(pos).readFromNBT(tag); } } // Tile entity providers should provide the class and name of their tile // entity here for registration. public abstract Class<? extends TileEntity> getTileEntityClass(); public abstract String getTileEntityName(); @Override public boolean hasTileEntity(IBlockState state) { return true; } // Generic createNewTileEntity so only the getTileEntityClass needs to be // specified. @Override public TileEntity createTileEntity(World world, IBlockState state) { try { return this.getTileEntityClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); return null; } catch (IllegalAccessException e) { e.printStackTrace(); return null; } } }
Block Base Class:
package com.icemetalpunk.chaotica.blocks; import com.icemetalpunk.chaotica.Chaotica; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.oredict.OreDictionary; public class ChaoticaBlockBase extends Block { public ChaoticaBlockBase(String name, Material materialIn) { super(materialIn); this.setUnlocalizedName(name).setRegistryName(new ResourceLocation(Chaotica.MODID, name)).setCreativeTab(Chaotica.tab); } protected void register() { GameRegistry.register(this); if (this instanceof ChaoticaTEBlock) { GameRegistry.registerTileEntity(((ChaoticaTEBlock) this).getTileEntityClass(), ((ChaoticaTEBlock) this).getTileEntityName()); } String[] oreDict = this.getOreDict(); if (oreDict != null) { for (String entry : oreDict) { OreDictionary.registerOre(entry, this); } } } // Override this if this block has an oredict entry. public String[] getOreDict() { return null; } }
Specific Block Class:
package com.icemetalpunk.chaotica.blocks; import javax.annotation.Nullable; import com.icemetalpunk.chaotica.Chaotica; import com.icemetalpunk.chaotica.gui.ChaoticaGuiHandler; import com.icemetalpunk.chaotica.tileentities.TileEntityChaoticCondenser; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class BlockChaoticCondenser extends ChaoticaTEBlock { public BlockChaoticCondenser() { super("chaotic_condenser", Material.ROCK); this.setHardness(3.5F); this.setSoundType(SoundType.STONE); this.register(); } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, @Nullable ItemStack item, EnumFacing side, float hitX, float hitY, float hitZ) { if (!world.isRemote) { player.openGui(Chaotica.instance, ChaoticaGuiHandler.Guis.CONDENSER.ordinal(), world, pos.getX(), pos.getY(), pos.getZ()); } return true; } @Override public Class<? extends TileEntity> getTileEntityClass() { return TileEntityChaoticCondenser.class; } @Override public String getTileEntityName() { return "ChaoticCondenser"; } }
How could the tile entity be created (it is!), its data be accessible (it is! It's displaying properly!), but the update method fail to be called, even though it works fine if I place down a fresh, "clean" block, just not when I place one down which already has tags?
How could it be final in the Block class? Then you would not be able to override it. You do know what final means, right? But yes, it does not hurt. Finality is good actually.Just because it's final in the Block class, so I kept it that way in my override. Probably not necessary, but it also doesn't hurt, right?Yes, I did think it was strange that I was able to override it, but being relatively new to Java, I thought there was some quirk of the language that allowed me to do it...turns out I'm just an idiot and confused the example code I was learning from (which declared it as final) with the base Block class itself
Sorry for the confusion!
-
You're not returning the item stack with the NBT which you set up (and that part looks ok). Instead you're returning an arraylist with a brand new ItemStack which has no NBT data at all:
return Lists.newArrayList(new ItemStack(this, 1, meta));
D'oh! This is what I get for trying to code at 5AM; how did I not see that? >_<
Unfortunately, fixing it to return Lists.newArrayList(ret) doesn't seem to fix the problem. It still drops nothing at all no matter how I harvest it.
Also, why are you making getItemDropped() return null? Looks unnecessary, especially as you've overridden getDrops(), which is what primarily calls getItemDropped() in the default Block#getDrops() implementation.I wasn't sure if there were certain cases where getItemDropped() was called instead of getDrops(), and if so, I didn't want it to drop anything different. Since I can't return an ItemStack with getItemDropped(), I just had it return null for safe measure.
But removing that override doesn't help; it still drops nothing.
(and any particular reason you've made getDrops() final?)Just because it's final in the Block class, so I kept it that way in my override. Probably not necessary, but it also doesn't hurt, right?
-
Solve one problem, another shows up.
I'm trying to simply make a block, which provides a tile entity, drop a tagged item stack when harvested. In other words, the item stack should have a BlockEntityTag with all the tile entity's data, ready to resume when placed down again.
Instead...I'm getting no drops at all. Whether I'm in Creative mode or Survival, using a tool or not, the block doesn't drop anything when broken.
Here's the relevant code:
@Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return null; } @Override public final ArrayList<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { int meta = state.getBlock().getMetaFromState(state); ItemStack ret = new ItemStack(this, 1, meta); NBTTagCompound nbt = new NBTTagCompound(); TileEntity te = world.getTileEntity(pos); te.writeToNBT(nbt); ret.setTagCompound(nbt); return Lists.newArrayList(new ItemStack(this, 1, meta)); } @Override public boolean canHarvestBlock(IBlockAccess world, BlockPos pos, EntityPlayer player) { return true; }
I'm returning an array containing the item stack from getDrops(), and I've ensured the block is harvestable at all times, so why isn't it dropping anything at all?
-
The ResourceLocation is wrong. You use
which points to"chaotica:fluids/corrosive_chaos_still.png"
The texture is located atassets/chaotica/fluids/corrosive_chaos_still.pngassets/textures/chaotica/fluids/corrosive_chaos_still.pngThe correct ResourceLocation would be
"chaotica:textures/fluids/corrosive_chaos_still.png"*Facepalm* I added "textures", but forgot the extension, then I added the extension and removed "textures"... Thank you! I don't know why I had it in my head that Minecraft would assume parts of the path, such as "textures" and ".png", for ResourceLocations being bound to textures.
Thanks again!
[SOLVED] [1.12] Registered SoundEvent not playing without error
in Modder Support
Posted
As I said, that's what I tried originally, and not only did the sound not play, but I got an error logged when trying to play the sound that it was an "empty sound". That's why I added the domain, and the error disappeared...