Jump to content

IceMetalPunk

Members
  • Posts

    402
  • Joined

  • Last visited

Everything posted by IceMetalPunk

  1. I'm using the AnvilUpdateEvent to create some custom anvil behavior when an item of mine is in the left slot of the anvil. It works perfectly! However, when the output is taken by the player, I'd like my item to remain in the left slot (with some damage, but that's the easy part). This is what I can't figure out how to do. It seems the AnvilRepairEvent is called before the left slot is cleared, and there's no way to stop that from clearing. So how do I either prevent the left slot from clearing, or else put the item back after it's cleared to create the illusion that it remained? Currently, I'm just giving the player the item in the AnvilRepairEvent, but it's quite annoying to do multiple anvil "crafts" if you have to keep putting it back into the anvil each time. *EDIT* Update: I've managed to get it working, but it's with a clearly very hacky workaround, and I don't like how it looks at all. I'll post my code below, but can anyone come up with a less... erm, messy solution? // Stupid, hacky workaround for there being no way to stop the left anvil // slot from clearing! public static HashMap<EntityPlayer, Pair<ContainerRepair, ItemStack>> anvilRefreshers = new HashMap<>(); @SubscribeEvent public void onTick(PlayerTickEvent ev) { if (anvilRefreshers.containsKey(ev.player)) { Pair<ContainerRepair, ItemStack> pair = anvilRefreshers.get(ev.player); pair.getLeft().putStackInSlot(0, pair.getRight()); anvilRefreshers.remove(ev.player); } } // Then, in the AnvilRepairEvent, when the proper item is in the left slot: if (player.openContainer instanceof ContainerRepair) { ItemStack give = ev.getItemInput().copy(); EntityPlayer player = ev.getEntityPlayer(); ContainerRepair cont = (ContainerRepair) player.openContainer; anvilRefreshers.put(player, Pair.of(cont, give)); } I cut out some irrelevant bits, but basically, I'm use the PlayerTickEvent to delay the inventory slot setting by 1 tick, thereby replacing the item in the slot 1 tick after it's been removed. It works perfectly, but... I mean, you can tell just from that type of the anvilRefreshers map that it's ugly code. Is there a better way?
  2. Ah... well, that's only a minor hiccup. I was only planning on using the dropper TileEntity to test all my rendering code, and once it was 100%, I was going to start working on my custom TileEntity and just re-bind the renderer. Guess I can't do things in that order after all; I'll have to finish the TE first and then working on rendering code. Thanks for your help!
  3. Okay... I think I know how to do that for custom tile entities (it's been awhile since I've worked with TEs, but I believe I remember the gist of it), but how would I do that for vanilla TEs like droppers? (Looking into their code, the dropper TE seems not to override the default TileEntity getUpdatePacket() method which just returns null... and actually, if that's the case that there's no syncing, how does the client display the proper items in a dropper inventory, then? O_O )
  4. *Sigh* Rendering code is biting me in the butt again. I have this TESR to render an item floating above a tile-entity providing block: package com.icemetalpunk.totemaltarations.render; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.RenderEntityItem; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntityDropper; import net.minecraftforge.items.IItemHandler; public class AltarPedestalTESR extends TileEntitySpecialRenderer<TileEntityDropper> { protected final RenderEntityItem rei; protected final EntityItem entity = new EntityItem(Minecraft.getMinecraft().world, 0, 0, 0, new ItemStack(Items.TOTEM_OF_UNDYING, 1)); protected int rotationControl = 0; protected final int INV_ROTATION_SPEED = 4; public AltarPedestalTESR() { super(); rei = new RenderEntityItem(Minecraft.getMinecraft().getRenderManager(), Minecraft.getMinecraft().getRenderItem()) { @Override public boolean shouldSpreadItems() { return false; } }; } @Override public void render(TileEntityDropper te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) { entity.setWorld(te.getWorld()); rotationControl = (rotationControl + 1) % this.INV_ROTATION_SPEED; if (rotationControl == 0) { entity.onUpdate(); } this.setLightmapDisabled(true); rei.doRender(entity, x + 0.5, y + 1.0f, z + 0.5, 0, partialTicks); this.setLightmapDisabled(false); } } As you can see by the generic type parameter, I'm currently testing this by binding it to dropper tile entities. It works perfectly fine! So my next step is to make it display the items that are actually in the inventory, instead of just the Totem of Undying. This is where things stopped working. I figured it should be a simple change. In the render() method, just after the entity.setWorld() call, I added entity.setItem(te.getStackInSlot(0)). Simple, right? But then, it stopped rendering anything at all. Some debugging later, and it turns out that getStackInSlot() is returning an empty ItemStack every time (with "air" as the item), regardless of the slot number, and even if I completely fill the inventory with things. The TESR is being bound (and instantiated) only in my client proxy; I don't know if that has something to do with it? Shouldn't the client still have access to the inventory's contents? And if not, how would I go about rendering the inventory contents in the world in a TESR if the client can't access that information?
  5. I have an event handler that I'm trying to use to automatically give the glowing effect to any mobs the player looks at while priming his bow. So I'm using this code (including all the debug output for now): @SubscribeEvent public void onPlayerUsingBow(PlayerTickEvent ev) { if (ev.phase == TickEvent.Phase.END) { EntityPlayer player = ev.player; ItemStack usingItem = player.getActiveItemStack(); int isInUse = player.getItemInUseCount(); if (usingItem.getItem() instanceof ItemBow && isInUse > 0) { RayTraceResult trace = player.rayTrace(80.0d, 1.0f); System.out.println("Type: " + trace.typeOfHit); System.out.println("Entity: " + trace.entityHit); System.out.println("Is Living?: " + (trace.entityHit instanceof EntityLivingBase)); if (trace.typeOfHit == RayTraceResult.Type.ENTITY && trace.entityHit != null && trace.entityHit instanceof EntityLivingBase) { EntityLivingBase livingEnt = (EntityLivingBase) trace.entityHit; livingEnt.addPotionEffect(new PotionEffect(MobEffects.GLOWING, 20)); System.out.println("Added glowing to " + livingEnt); } } } } According to the debug output, though, the RayTraceResult's type is ALWAYS Block, even if I'm staring directly at a zombie or some such mob. Like, I can be just one block away, aiming directly at the zombie's head or body, and it still gives me a Block type result with a null entityHit. Am I misunderstanding how to use the EntityPlayer#rayTrace method, or is there a better way to go about finding which mob the player is looking at (within 80 blocks or so)?
  6. Are you calling LootTable.register() in your pre-init event handler?
  7. Have you tried a simple iteration over the enum's values, comparing to their ordinals? for (EnumFacing face : EnumFacing.values()) { if (meta == face.ordinal()) { iblockstate = iblockstate.withProperty(FACING, face); break; } } Or, even smaller, just use the array index directly: iblockstate = iblockstate.withProperty(FACING, EnumFacing.values()[meta]); You might want to do some sanitizing on that version, but it's pretty concise as-is.
  8. For the recipes, yes; but you still need to register the items.
  9. In your case, are you registering the tm:tutorial_ingot in the RegistryEvent<Item> handler?
  10. As it says, the property "age" doesn't exist in the block "ppextreme:tungstenlight". Does your block have a property called "age", and are you returning the proper block state container in the block's createBlockState method?
  11. I'm *not* doing anything with its rotation... and it's just not rotating at all... As for the lighting, I *didn't* disable lighting at first, and it was black; that's why I tried disabling lighting, but it's still black. Either way I tried that, it still turns out black. *EDIT* A little bit of debug output shows me that the age of the EntityItem is *not* ticking up. I'm going to look into that more, but I assume that's because it's not spawned in the world? At the same time, I don't *want* it spawned in the world as an entity, I'm only using it for rendering, so... how do I get its age to tick up without spawning it? *EDIT 2* Problem 1 is solved! Turns out that the age is ticked up in the onUpdate() method, and that's only called naturally for entities spawned in a world. So I just manually call onUpdate() now, immediately after setting the entity's world, and it spins perfectly normally! Now I just need to figure out how to get the colors/lighting correct.... any ideas? *EDIT 3* AHA! Solved it! I stumbled upon the solution completely accidentally, really I was going to remove the super.render() call, since I didn't want the nameplate to render, and I figured I should check that method to make sure it's not doing anything else important that I might need to keep. It's not, but in that method, before rendering the nameplate, it calls the setLightmapDisabled method. That method doesn't use GlStateManager.disableLighting() at all -- instead, it disables a lighting map texture. So I removed the super.render() call and tried using setLightmapDisabled in my rendering code instead... and it worked! The item now renders perfectly fine Thank you for your help, Draco!
  12. What do you mean it doesn't work "online"? And you don't need to reference worldIn for your particular code, as EntityPlayer#rayTrace simply uses the world that's bound to the player instance.
  13. I realized that for the final product here, I was only going to need to replace entities from the PlayerDropsEvent list, and ultimately I got what I wanted working without having to deal with the /give issue. But I'd still like to know how I might go about fixing the problem in case I do need a more general item-entity-replacement approach like this in the future?
  14. Doesn't the RayTraceResult provide the position of the block you're looking at? If so, then teleporting the player to that location would of course teleport them into the block. You'll want to call BlockPos#offset() before grabbing the coordinates, to offset the position based on the RayTraceResult's sideHit value (it's a public member).
  15. You can get the world saves folder quite easily: DimensionManager.getCurrentSaveRootDirectory(); That gives you the current world's folder, so one level up is the "saves" directory, and one level above that is the main ".minecraft" directory. As for unzipping it, the standard java.util.zip package contains the classes/methods you need to extract files. Unloading the current world and loading the new one, though... that's beyond my scope of knowledge.
  16. You'll need to look into Capabilities (I'm 95% sure they existed in 1.8). But basically, once you have the Tile Entity, you can get its ITEM_HANDLER_CAPABILITY , then use that Capability's insertItem, extractItem, etc. methods to manipulate the inventory as you wish.
  17. SOLVED! The solution to the rotation issue is to call EntityItem#onUpdate manually, since it's not called automatically unless the entity is spawned in the world (and thus the age of the entity, which controls its rotation, doesn't get updated). The solution to the black-rendering issue is to use the setLightmapDisabled method instead of GlStateManager.disableLighting(), as there's apparently a texture map used for lighting when rendering, and that needs to be disabled to get a full-color render regardless of lighting conditions. Original Post: Let me start by saying that rendering has always been my weakest area of programming. In any language, ever. I don't know why, but it's always been difficult for me. So now I'm playing around with TESRs, trying to learn how to use them, and immediately I've hit a roadblock. The idea was simple: use a RenderEntityItem in a TESR bound to (for now) the TileEntityDropper to display a Totem of Undying floating above the droppers. So I created this TESR: public class AltarPedestalTESR extends TileEntitySpecialRenderer<TileEntityDropper> { RenderEntityItem rei = null; public AltarPedestalTESR() { super(); rei = new RenderEntityItem(Minecraft.getMinecraft().getRenderManager(), Minecraft.getMinecraft().getRenderItem()) { @Override public boolean shouldSpreadItems() { return false; } }; } @Override public void render(TileEntityDropper te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) { EntityItem entity = new EntityItem(te.getWorld()); entity.setItem(new ItemStack(Items.TOTEM_OF_UNDYING, 1)); GlStateManager.pushMatrix(); GlStateManager.pushAttrib(); GlStateManager.color(1.0f, 1.0f, 1.0f); GlStateManager.disableLighting(); rei.doRender(entity, x + 0.5, y + 1.0f, z + 0.5, 0, partialTicks); GlStateManager.enableLighting(); GlStateManager.popAttrib(); GlStateManager.popMatrix(); super.render(te, x, y, z, partialTicks, destroyStage, alpha); } } And I'm registering it in my Client Proxy's Init event handler with this: ClientRegistry.bindTileEntitySpecialRenderer(TileEntityDropper.class, new AltarPedestalTESR()); It is rendering the totem above the droppers, but it's rendering it totally black and spinning very, very quickly. I tried to fix the black color by adding the GlStateManager method calls you see in the code (setting the color to (1.0,1.0,1.0), which is white, right? And disabling the lighting), but it didn't fix the problem, and I don't really understand rendering enough to know what to try next. As for the rotation, I looked into the rendering code a bit more and it seemed like the rotation was based on the EntityItem's age. I reasoned that, therefore, creating a new EntityItem each render tick was probably a bad idea, so I moved the EntityItem initialization out of the method and into the class itself, resulting in this code: public class AltarPedestalTESR extends TileEntitySpecialRenderer<TileEntityDropper> { RenderEntityItem rei = null; EntityItem entity = new EntityItem(Minecraft.getMinecraft().world, 0, 0, 0, new ItemStack(Items.TOTEM_OF_UNDYING, 1)); public AltarPedestalTESR() { super(); rei = new RenderEntityItem(Minecraft.getMinecraft().getRenderManager(), Minecraft.getMinecraft().getRenderItem()) { @Override public boolean shouldSpreadItems() { return false; } }; } @Override public void render(TileEntityDropper te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) { entity.setWorld(te.getWorld()); GlStateManager.pushMatrix(); GlStateManager.pushAttrib(); GlStateManager.color(1.0f, 1.0f, 1.0f); GlStateManager.disableLighting(); rei.doRender(entity, x + 0.5, y + 1.0f, z + 0.5, 0, partialTicks); GlStateManager.enableLighting(); GlStateManager.popAttrib(); GlStateManager.popMatrix(); super.render(te, x, y, z, partialTicks, destroyStage, alpha); } } It stopped the crazy spinning, but it also stopped the spinning completely, so the item doesn't turn anymore. I don't know where to go from here... So the two questions are: 1) How do I get it to rotate at a normal EntityItem speed? 2) How do I get it to render normal-colored instead of black?
  18. ...so, this appears to be not completely solved after all. And after I merged it into my master branch, too. (Lesson learned: do full testing before merging.) So here's the newest code: https://github.com/IceMetalPunk/TotemEssentials/blob/827f3c291734ba60f102b464207252faf3806fad/src/main/java/com/icemetalpunk/totemessentials/events/TEEvents.java#L355 In this version, the only item entities replaced with the fireproof versions are the ones with the "Fireproof:1b" tag, and that tag is removed once the replacement happens. That much works flawlessly. The issue is that if the player is given items with the /give command (or, I presume, an advancement reward, though I haven't tested that part), it duplicates the items. It's like the item entity spawned to give to the player is still added to the player's inventory even though the code is supposed to prevent it from joining the world at all; but it also still creates the fireprooof version, so the player picks up both. I've tried testing the value of item.getOwner(), since that's used only in these give command scenarios, but that's not set until *after* the entity is spawned (it returns null in every case, even *with* the commands used), so that won't work here.
  19. Ohhhh.... is that what "tracking range" means? I thought it had something to do with mob AI tracking for some reason. (I know, it didn't really make a ton of sense, especially since it's a generic entity registration and not just for mobs... but I couldn't figure out what it meant otherwise!) Yep, changing that value did, in fact, fix the problem! Thank you so very much!
  20. Here's the repo and branch I'm working on this on: https://github.com/IceMetalPunk/TotemEssentials/tree/fireproof-items The body of the pre-init handler in the main class instantiates the TERegistryEvents instance, and that constructor is where the entity registration happens. *EDIT* (The git branch is deleted now that the issue was fixed thanks to jabelar's suggestion!)
  21. I use this code, basically in the PreInit event: EntityRegistry.registerModEntity(new ResourceLocation(TotemEssentials.MODID, "fireproof_item"), EntityItemFireproof.class, "fireproof_item", entityID++, TotemEssentials.instance, 5, 1, true); (entityID is a variable that starts at 0 and is only used here.)
  22. 1. I can't use hasCustomEntity/etc. because I want the fireproofing to apply to all item entities, including vanilla ones and ones from other mobs. 2. Thanks for the tip; I will be doing that going forward. 3. See #2 4. ... *facepalm*. This is what I get for having copypasta in a piece of code where I know what I meant so I didn't see what I actually wrote. Damnit. Thank you! So now that I fixed those things, the items are thrown properly... but weirdly, they seem to stop rendering after only being a few blocks away. The EntityItemFireproof, that is. If I move only 5 or 6 blocks away, they stop rendering, and when I move closer, they render again. I'm pretty sure normal items render from farther away than that, don't they? Is there some special rendering setup I need to do for custom item entities?
  23. And here I thought canceling the Join World event would kill the item inherently. Guess not. I've *almost* got it working with this code: @SubscribeEvent public void onItemCreate(EntityJoinWorldEvent ev) { Entity ent = ev.getEntity(); World world = ev.getWorld(); if (ent instanceof EntityItem && !(ent instanceof EntityItemFireproof)) { EntityItem item = (EntityItem) ent; EntityItemFireproof fireproofItem = new EntityItemFireproof(world, item.posX, item.posY, item.posZ, item.getItem()); // Age and pickup delay must be set so you don't immediately pick up // thrown items, but they're private values, so we use Reflection // for it. Field ageField = ReflectionHelper.findField(EntityItem.class, "age", "field_70292_b", "d"); Field delayField = ReflectionHelper.findField(EntityItem.class, "delayBeforeCanPickup", "field_145804_b", "e"); int age = item.getAge(); try { int delay = delayField.getInt(item); delayField.setInt(fireproofItem, delay); ageField.setInt(fireproofItem, age); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } // Here's where the motion is... fireproofItem.motionX = item.motionX; fireproofItem.motionY = item.motionX; fireproofItem.motionZ = item.motionX; world.removeEntity(item); world.spawnEntity(fireproofItem); } } The only problem is that when the player tosses an item, the motion seems to be set *after* the spawning, so I can't actually copy the proper motion. Instead, the items just all fall the same way regardless of the direction the player is facing. How do I solve that order-of-events issue?
  24. I'm trying to make certain item entities immune to fire. Turns out, that's not as easy as it seems. So for a first test, I'm trying to make *all* item entities immune to fire by creating a class, EntityItemFireproof, that extends EntityItem, but overrides its attackEntityFrom() method to ignore fire damage. Then I'm using the EntityJoinWorldEvent to "replace" all item entities with my Fireproof versions. *EDIT* Okay, this particular issue has been mostly solved. But now I can't get the replaced items to properly copy the original item entity's motion when thrown, since it seems that's set *after* the EntityJoinWorldEvent fires; see this post for the current issue. Previous, but related, issue: Upon testing, I drop an item... and suddenly there are infinitely many copies being made, without stop, until the game slows and crashes from too many entities. I'm canceling the Join World event and I'm not spawning more entities when my Fireproof entities are created, so what could be causing this? Here's the event handler code: @SubscribeEvent public void onItemCreate(EntityJoinWorldEvent ev) { Entity ent = ev.getEntity(); World world = ev.getWorld(); if (ent instanceof EntityItem && !(ent instanceof EntityItemFireproof)) { EntityItem item = (EntityItem) ent; EntityItemFireproof fireproofItem = new EntityItemFireproof(world, item.posX, item.posY, item.posZ, item.getItem()); fireproofItem.motionX = item.motionX; fireproofItem.motionY = item.motionX; fireproofItem.motionZ = item.motionX; world.spawnEntity(fireproofItem); ev.setCanceled(true); } } And here's the EntityItemFireproof class: package com.icemetalpunk.totemessentials.items; import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.util.DamageSource; import net.minecraft.world.World; public class EntityItemFireproof extends EntityItem { public EntityItemFireproof(World worldIn) { super(worldIn); } public EntityItemFireproof(World worldIn, double x, double y, double z) { super(worldIn, x, y, z); } public EntityItemFireproof(World worldIn, double x, double y, double z, ItemStack stack) { super(worldIn, x, y, z, stack); } @Override public boolean attackEntityFrom(DamageSource source, float amount) { if (source.isFireDamage()) { return false; } else { return super.attackEntityFrom(source, amount); } } } So why on Earth would that little event handler lead to infinite item spawns when I drop an item? *EDIT* A bit of debugging later shows that the duplicated entity is just an EntityItem, not an EntityItemFireproof. But how is that possible when I'm not spawning any more EntityItems, only an EntityItemFireproof? I thought maybe the vanilla drop code was detecting the failure to spawn an item and trying again repeatedly, but that doesn't look like the case as I look through the vanilla code (unless I missed where that happens?). So what's going on here?
  25. Well... that's what I've done, then. And it works! Except it required a lot of reflection, since many of the generators are in private or protected fields, and the initialization method is also protected... It feels quite hacky. But it works! Can you take a look at the code I've added and tell me if you can think of a less... reflection-heavy way of accomplishing this? https://github.com/IceMetalPunk/TotemEssentials/blob/c1bfa555a3c1c5e470ce4860add62dfaea5942fe/src/main/java/com/icemetalpunk/totemessentials/events/TEEvents.java#L157
×
×
  • Create New...

Important Information

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