-
Posts
83 -
Joined
-
Last visited
Everything posted by JayZX535
-
[1.14.4] Using .containerItem() to leave behind an item with NBT data?
JayZX535 replied to JayZX535's topic in Modder Support
Unfortunately no. I tried adding a custom extension to properties in my Item class, but the problem is, the method is this: public Item.Properties containerItem(Item containerItemIn) { this.containerItem = containerItemIn; return this; } Which takes an Item and not an ItemStack. Good thought though... -
[1.14.4] Using .containerItem() to leave behind an item with NBT data?
JayZX535 replied to JayZX535's topic in Modder Support
Oh yeah, I know how to edit the NBT data for the result item, which goes into the output slot. I just don't know how to edit the NBT data for an item that gets left behind in the crafting grid, like buckets from the cake recipe, or (in 1.15) empty bottles after crafting a honey block. -
[1.14.4] Using .containerItem() to leave behind an item with NBT data?
JayZX535 replied to JayZX535's topic in Modder Support
That was my first thought but the method that does it, getRemainingItems(C inv) comes from the IRecipe interface and is a default, so I can't just override and insert my own code. Which is a shame because the method itself would be easy enough to alter. -
Hey all, I have a set of items that can be dyed dynamically (think leather armor, but simpler-- just the main 16 colors). This works by assigning an NBT tag to the dyed ItemStack, which the game then checks for when applying tints to the layer. This function itself works fine, however I've run into a bit of a block when trying to add additional functionality. Put simply, this item can be crafted with another item to make a 'combined' item. I'd like to make it possible to un-craft that combination, returning the item crafted with it in the output slot, and leaving the base item in the crafting grid (i.e. buckets after crafting cake). There are multiple items that can be crafted with the base item, which are also saved in the stack NBT data, so I'd like to keep those secondary items as the output, since that seems like it should be easier to determine which item to output that way. However, as I understand it, if I just use the default .containerItem() to return the base item, it will create a new stack of that item, thus wiping the NBT (and any color data that might have been stored in it). Is there a good way I could ensure that the color NBT data is copied over to the base item, so that it doesn't revert to its un-dyed version upon crafting? Thanks, and have a great day.
-
Thank you so much-- this helped me a lot! Blocks seem to handle containers differently than most other things-- Forge handles them a bit better inherently (which is as to be expected-- most GUIs would be coming from blocks, after all). I eventually also found the registry method that allows me to send data with the container. I used that to pass the entityID, allowing me to register it as... event.getRegistry().register(IForgeContainerType.create((windowId, inv, data) -> { int id = data.readInt(); return new WCCanineEntityContainer(windowId, inv, id); }).setRegistryName("wc_canine_inventory")); It's now up and running as expected, so thank you again for your help!
-
Apologies for the massively delayed response. I've been troubleshooting... a lot 9.9 I was a little bit blind and was looking at the wrong method in the blocks. Blocks use this to open GUIs... public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { player.openContainer(state.getContainer(worldIn, pos)); return true; } Which works. Well, kind of. The game now tries to open the GUI-- before erroring and crashing. It's having issues with the inventory container, and in particular, the inventory getting passed to it being null. Which brings up a totally different problem... The registry: public static ContainerType<WCTradingPostContainer> WC_TRADING_POST_CONTAINER; public static ContainerType<WCKibblePressContainer> WC_KIBBLE_PRESS_CONTAINER; public static ContainerType<WCCanineEntityContainer> WC_CANINE_INVENTORY_CONTAINER; @SuppressWarnings ("unchecked") public static void registerContainerTypes(final RegistryEvent.Register<ContainerType<?>> event){ event.getRegistry().registerAll( WC_TRADING_POST_CONTAINER = (ContainerType<WCTradingPostContainer>) new ContainerType<WCTradingPostContainer>(WCTradingPostContainer::new).setRegistryName("wc_trading_post"), WC_KIBBLE_PRESS_CONTAINER = (ContainerType<WCKibblePressContainer>) new ContainerType<WCKibblePressContainer>(WCKibblePressContainer::new).setRegistryName("wc_kibble_press"), WC_CANINE_INVENTORY_CONTAINER = (ContainerType<WCCanineEntityContainer>) new ContainerType<WCCanineEntityContainer>(WCCanineEntityContainer::new).setRegistryName("wc_canine_inventory") ); } Relevant part of the container code... public WCCanineEntityContainer(int windowId, PlayerInventory playerInv) { this(windowId, playerInv, null); } public WCCanineEntityContainer(int windowId, PlayerInventory playerInv, final WCAnimalEntity animal) { super(WCRegistry.WC_CANINE_INVENTORY_CONTAINER, windowId); this.animal = animal; System.out.println(animal); this.animalInventory = animal.animalInventory(); animalInventory.openInventory(playerInv.player); } That print statement indicates that "animal" is null. I'm passing the animal in through the getContainer method I use to open the GUI... @Nullable @Override public INamedContainerProvider getContainer() { return new SimpleNamedContainerProvider((windowId, playerInv, name) -> { return new WCCanineEntityContainer(windowId, playerInv, this); }, this.getTranslationText()); } but I assume that's being overridden by the registry seems to call the first method, which passes the animal as "null". The block guis get around it by using this... public WCKibblePressContainer(int windowId, PlayerInventory playerInv) { this(windowId, playerInv, IWorldPosCallable.DUMMY); } public WCKibblePressContainer(int windowId, PlayerInventory playerInv, final IWorldPosCallable worldPos) { super(WCRegistry.WC_KIBBLE_PRESS_CONTAINER, windowId); this.worldPos = worldPos; } So... I can only assume that the difference comes from that "IWorldPosCallable.Dummy", unless I've just been staring at this for so long that I'm missing something glaring. But I don't have any sort of dummy method to use instead of null, and frankly I'm not quite sure how to make one. The animal itself does get initialized properly, so it shouldn't be an issue there? I feel like I'm missing something big, and I have yet to find an example of a working entity inventory to go off-- aside from horses, which have their own special opener hard-coded into the player (as mentioned previously). Anyone know how I could get around this?
-
Hey all, I'm currently in the process of trying to implement an inventory for an entity. I want the player to be able to click the entity and access its inventory. So far I've been basing a lot off the horse classes, however the horse handles opening the gui by calling playerEntity.openHorseInventory(this, this.horseChest); , but since my entity isn't connected to the horse classes, that's not gonna work for me. Is there another way I can open the entity's GUI? I think everything else should be set up beyond that-- it's just a matter of opening the GUI in the first place. I assume registration is the same for an entity container as for a tileentity container, so unless that's different I think everything else should work... Thanks!
-
[1.14.4+] Unlocking Lore Book Sections as Player Progresses
JayZX535 replied to JayZX535's topic in Modder Support
Apologies for the delayed response. Sounds like I have some options to play around with when setting this up-- thanks! I'll keep these in mind for when I start adding lore! -
Hey all, I've got a few theoretical questions pertaining to an in-game mod manual. I've seen a lot of mods (especially tech ones) implementing their own lore/guide books, so that the player doesn't have to constantly toggle back and forth with the wiki to figure out what they're doing. The mod I'm working on has quite a bit of complexity to it, so I'd like to implement something similar-- a book you can refer back to if you're curious about how something works. There are a couple of caveats about how I'd like to do that, though, and I'm wondering how possible/easy/efficient they'd be to implement. First off, I'd like to make the info reveal a bit at a time as the player discovers stuff-- sort of like how the advancement system works. And secondly, I'd like to tie the information to the player itself, so if they die and lose their book, they can make a new one and the information is still there. (lore-wise, the book is considered to be magic and soul-bound). My first thought was that the capability system is probably the way to go. However, this book has the potential to hold a lot of unlockable segments. So for example, you might unlock the general category for an entity, which leads you to 5/6 more detailed categories about its regional traits, which could lead to even more details that unlock separately under each of those categories, depending on how much this player learns about the entity. It's a tree, much like the advancement system. So if I put that into a capability, I feel like it's just going to be a lot of "has the player unlocked this? y/n" booleans. That might not be bad? But I'm curious if there'd be a more efficient way of doing this, or if I just do need to store everything in a capability with a lot of booleans. Also, is it probably best to just store all the lore translations in the lang file the way advancements are, even if they're longer blocks of text (like, whole paragraphs/multiple paragraphs)? Or should I try to set up a different system of, say, storing them in .json files or something and have some other way of indicating which language they are? It's worth noting that I'm not locked into using the 1.14 update for this. If 1.15 introduces any changes that would make this easier, I'm not opposed to waiting until I upgrade the mod to add this in. Anyway, I'm not sure if I'm on the right track with this idea or not, but I figured I'd try and get some feedback on it before I start practically implementing it, so that if I do need to make tweaks I can do it while I'm still theory-crafting in the first place. Thank you for your time!
-
[1.14.4] Syncing rendered held item movement with head?
JayZX535 replied to JayZX535's topic in Modder Support
Hey again TGG, Thank you so much for the advice (and validation that this is heckin confusing haha). After a lot of fiddling, I was finally able to figure out the string of issues that was causing problems. In case anyone else ends up finding this later in search of help, here's what I ended up doing to solve my issues. Firstly, as it turns out you can't just use the yaw of the head, since that doesn't account for the model rotation. The headNetYaw variable calculates that difference out, so unless you mirror that rotation, you're better off using the variable itself. So I switched back to that method. To get around the issue of having multiple poses, some with fixed head position and some with dynamic, I built in some methods to the model class to check the entity's pose and return the proper value for the head position. I designed them to return either the raw version of the variable (needed for the item rotation), or the calculated one (needed for the rotation of the actual model parts), which allowed me to ensure that the proper result would be returned in both cases. This avoids the issue of having to write up a checker code within the item renderer itself, and that way I only have to worry about changing one set of code if I make any tweaks. Lastly, I finally figured out the biggest stumper, which was the fact that the rotation was still crooked even with the synchronized method. I tested each one individually by forcibly returning zero on the two I wasn't using, and determined that individually, they were all doing what they should be. However, they were messing up when combined. As it turned out, I had the order of rotation different on the item renderer (pitch > yaw > tilt) than on the entity model (tilt > yaw > pitch). Changing the rotations on the item class to match the order of the ones on the entity model solved the problem. So it did indeed come down to the order of transformation in the end. Definitely one of the tripper problems I've dealt with, but I'm happy to report I finally have it solved. Thank you guys again for your help! -
[1.14.4] Syncing rendered held item movement with head?
JayZX535 replied to JayZX535's topic in Modder Support
Hmmm. That's sort of what I was trying to do? I was attempting to compensate with the different pivot point of the head and item by setting the item to the head's rotation point, rotating it, and then positioning it at the mouth from there. Is the pivot point of the item the same as its origin? If not that could be screwing it up... Here's a more detailed breakdown of what this is (or is supposed to) do... float rotMultiplier = (float)Math.PI / 180F; GlStateManager.translatef((this.getEntityModel().getHead().rotationPointX / 16F), (this.getEntityModel().getHead().rotationPointY / 16F), (this.getEntityModel().getHead().rotationPointZ / 16F)); Sets a standardized rotation amount (and I'm not sure if this is correct, but it's the inverse of the calculations used to set the head animations for the entity model, and it looks like the item rotations should take the actual amounts-- so this should reverse it?), and then sets the item to the rotation point of the head. float calcHeadPitch = this.getEntityModel().getHead().rotateAngleZ / rotMultiplier; GlStateManager.rotatef(calcHeadPitch, 1.0F, 0.0F, 0.0F); float calcHeadYaw = this.getEntityModel().getHead().rotateAngleY / rotMultiplier; GlStateManager.rotatef(calcHeadYaw, 0.0F, 1.0F, 0.0F); float calcHeadTilt = this.getEntityModel().getHead().rotateAngleX / rotMultiplier; GlStateManager.rotatef(calcHeadTilt, 0.0F, 0.0F, 1.0F); Gets the X, Y, and Z rotation values from the head and applies them to the item. GlStateManager.translatef(0.001F, 0.1F, -0.3F); GlStateManager.rotatef(-90.0F, 1.0F, 0.0F, 0.0F); this.itemRenderer.renderItem(itemstack, entityIn, TransformType.GROUND, false); Translates the item to where it should be in the dog's mouth, rotates it 90 degrees (to make it lay flat), and then renders it. Note, the TransformType.GROUND does throw a deprecation error, which leads me to net.minecraftforge.client.extensions.IForgeBakedModel.handlePerspective(TransformType cameraTransformType) instead, but I'm trying to figure out how to actually use that? I'm not sure if that's what's causing the issue or not but it's worth noting... -
[1.14.4] Syncing rendered held item movement with head?
JayZX535 replied to JayZX535's topic in Modder Support
Shoot, that explains some things, hah-- thanks. Went ahead and swapped them, but it's still being a little funky... Updated code: @SuppressWarnings("deprecation") @OnlyIn(Dist.CLIENT) public class WCWolfHeldItemLayer extends LayerRenderer<WCWolfEntity, WCWolfModel<WCWolfEntity>> { private final ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); public WCWolfHeldItemLayer(IEntityRenderer<WCWolfEntity, WCWolfModel<WCWolfEntity>> wcwolf) { super(wcwolf); } public void render(WCWolfEntity entityIn, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch, float scale) { ItemStack itemstack = entityIn.getStackInSlot(entityIn.getHeldSlotID()); if (!itemstack.isEmpty()) { GlStateManager.pushMatrix(); float rotMultiplier = (float)Math.PI / 180F; GlStateManager.translatef((this.getEntityModel().getHead().rotationPointX / 16F), (this.getEntityModel().getHead().rotationPointY / 16F), (this.getEntityModel().getHead().rotationPointZ / 16F)); float calcHeadPitch = this.getEntityModel().getHead().rotateAngleZ / rotMultiplier; GlStateManager.rotatef(calcHeadPitch, 1.0F, 0.0F, 0.0F); float calcHeadYaw = this.getEntityModel().getHead().rotateAngleY / rotMultiplier; GlStateManager.rotatef(calcHeadYaw, 0.0F, 1.0F, 0.0F); float calcHeadTilt = this.getEntityModel().getHead().rotateAngleX / rotMultiplier; GlStateManager.rotatef(calcHeadTilt, 0.0F, 0.0F, 1.0F); GlStateManager.translatef(0.001F, 0.1F, -0.3F); GlStateManager.rotatef(-90.0F, 1.0F, 0.0F, 0.0F); this.itemRenderer.renderItem(itemstack, entityIn, TransformType.GROUND, false); GlStateManager.popMatrix(); } } public boolean shouldCombineTextures() { return false; } } -
Hello, I have a dog entity that can carry food items in its mouth (much like foxes). I'm trying to make its held item actually render there as it eats, but I'm having a little trouble getting it to actually work properly. When the dog is standing still it works fine. However, when the dog moves its head to look at the player, tilting it in a certain way, it goes all askew for a bit until the dog fully stops moving. I've been looking at the fox's head movement in particular, but that class has a lot of variables and functions that still have the default names, which is giving me a hard time tracing what they're used for. It has a specific parameter to account for Z Axis tilt, but it's hard to figure out what conditions are actually causing it to be used and for what. My dog entities also have a lot of potential poses, so the more universalized my solution can be, the better. Right now the code I have is this, which works alright while the dog is perfectly still but when it looks around (particularly when turning its head at an angle to the player), the rendered item does that weird tilting. @SuppressWarnings("deprecation") @OnlyIn(Dist.CLIENT) public class WCWolfHeldItemLayer extends LayerRenderer<WCWolfEntity, WCWolfModel<WCWolfEntity>> { private final ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); public WCWolfHeldItemLayer(IEntityRenderer<WCWolfEntity, WCWolfModel<WCWolfEntity>> wcwolf) { super(wcwolf); } public void render(WCWolfEntity entityIn, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch, float scale) { ItemStack itemstack = entityIn.getStackInSlot(entityIn.getHeldSlotID()); if (!itemstack.isEmpty()) { GlStateManager.pushMatrix(); float rotMultiplier = (float)Math.PI / 180F; GlStateManager.translatef((this.getEntityModel().getHead().rotationPointX / 16F), (this.getEntityModel().getHead().rotationPointY / 16F), (this.getEntityModel().getHead().rotationPointZ / 16F)); float calcHeadPitch = this.getEntityModel().getHead().rotateAngleX / rotMultiplier; GlStateManager.rotatef(calcHeadPitch, 1.0F, 0.0F, 0.0F); float calcHeadYaw = this.getEntityModel().getHead().rotateAngleY / rotMultiplier; GlStateManager.rotatef(calcHeadYaw, 0.0F, 1.0F, 0.0F); float calcHeadTilt = this.getEntityModel().getHead().rotateAngleZ / rotMultiplier; GlStateManager.rotatef(calcHeadTilt, 0.0F, 0.0F, 1.0F); GlStateManager.translatef(0.0F, 0.1F , -0.3F); GlStateManager.rotatef(-90.0F, 1.0F, 0.0F, 0.0F); GlStateManager.translatef(0.001F, 0.0F, 0.0F ); this.itemRenderer.renderItem(itemstack, entityIn, TransformType.GROUND, false); GlStateManager.popMatrix(); } } public boolean shouldCombineTextures() { return false; } } Stuff like the Math.PI calculation comes from what I've observed in other entity classes and it seems to be working at least in part? My current method here attempts to get the tilt value directly from the head itself. But that's still causing problems. So I'm wondering if maybe I'm getting the rotation value wrong? The value used in the model class seems to be handled differently than the rotation value here. Putting them in one-for-one causes negligible movement on the item while the head moves a lot. In the model class, the inputs like netHeadYaw and headPitch seem to be divided by that Math.PI / 180F value, whereas in the fox held item class it seemed like those values were inputted directly to the held item. There's not a visible tilt value though, not that I've found, and I have some custom animations defined within the model class that I need to account for. That's why I want to get the value directly from the head rotation if possible-- otherwise I'll have to figure out a way of patterning all the checks I do in the model class somehow, and I really don't want to have to have both classes running the same checks for pose and such if I can help it. Anyone else have an idea of what I could try here? Thanks.
-
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Thank you! Hopefully what I learned here can benefit others too -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Sorry for the wait! I didn't use a self-contained project for this unfortunately, but these are the relevant parts of code I used to reference it. I assign a new texture handler from my ClientProxy, and use that to retrieve the handler to get the instance for my entity. Hopefully this should still be fairly easy to set up and test? Gist I didn't include the methods from my entity class used to get stuff like texture dimensions, path, etc. but you could easily put something static in instead. Those methods are just designed to standardize things so that I can more easily add new animals and their genetics in the future. Thank you again for all your help! Also, if you notice anything that I could streamline or that I'm not doing quite right, I'm all ears. Thanks! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Sure thing! Let me finish up a few last things and clean/comment it. Would you prefer I share the whole renderer class, or just the parts that deal with the buffered image manipulation? -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Thank you for all your help! I tried intentionally setting the texture to a specific color, and it soon became apparent that it wasn't an issue with my color-setting. Even Java's default colors returned bizarre results. I couldn't see anything wrong with the in-game tinting, so I did some more research and testing. And... apparently it was actually an issue with Java reading the colors in as ABGR instead of ARGB. I'm not sure if this is due to me having missed a Java update or something, but I'm gonna be looking into that. In any case, it was reading my red value as blue, which is why everything was so bizarrely tinted. Built a function to swap those around and it seems to work beautifully, from what I've seen thus far. I'll probably also build a texture correction toggle into my config file, because if it's a java issue then I expect there could be potential problems depending on what's installed on user-end too. Thank you so much for all your time and help. I think I've finally got this all nailed down? If not I suppose I'll have to pop in with more questions haha. But I really appreciate it-- this seems to be a much more lightweight method than Minecraft's layer system, in addition to avoiding the Z fighting and flickering, so that's absolutely fantastic! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Thank you again for all your time and help! I think I'm slowly getting the hang of this... So, I've kept playing around with this and had much more success. I also figured out what was going on with the for loops: I was having it print out the values of the pixels, which although it's a great debugging tool, apparently I'd severely underestimated its impact on performance. I'll be removing those troubleshooting println()s for the final version, and without them the lag is much more bearable-- only a few seconds even for a large number of entities. So that should be a non-issue. You were right in that I was accidentally drawing a fully transparent texture. I've continued messing around with it and now that's no longer the case! Graphics does work as well, I was also just using it wrong. I'm now using setComposite to combine layers, but when it comes to applying color I've had the best luck using for loops to multiply each pixel. So far that seems to be working almost perfectly. However, there's one remaining problem. Somehow, somewhere, the colors aren't rendering true. They're a little-- or in some cases a lot shifted. And it seems to be on the actual rendering and not the calculations? For example, I printed the RGB values used to set a pixel color for one dog's base color and got "0.73356414, 0.64879674, 0.5183853". When inputted into this color calculator, it shows up as a sandy yellow-brown. However the dog itself... It looks like the color is being assigned properly? There's a slight bit of deviance between the number I put into the color and the one I get out, but it's a difference of 0.0015 or so at most, which I don't think should be enough to shift the color value that drastically?? So I'm thinking it may have something to do with the color mode of the image and Java shifting colors that don't quite align with what it's seeing? Do you know how I could get Java to base the image color model around the actual colors I'm putting in? Or is something else going wrong? The actual colors coming from my print statements have seemed spot on when I put them into that color site, so this one has me stumped... Code is as follows... //img comes from another method that loads a greyscale texture from a file as a BufferedImage.TYPE_INT_ARGB . I've also been using BufferedImage.TRANPARENT . Not sure which is better but neither has fixed my problem. private BufferedImage applyColor(BufferedImage img, Color tint) { BufferedImage tintedImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = tintedImg.createGraphics(); graphics.drawImage(img, 0, 0, null); graphics.dispose(); float redBase = (float) tint.getRed() * (1/255F); float greenBase = (float) tint.getGreen() * (1/255F); float blueBase = (float) tint.getBlue() * (1/255F); for (int i = 0; i < tintedImg.getWidth(); i++) { for (int j = 0; j < tintedImg.getHeight(); j++) { //I want to keep the alpha value of the source while only changing its color float alpha = (float) tintedImg.getColorModel().getAlpha(tintedImg.getRaster().getDataElements(i, j, null)) * (1/255F); float redTint = (float) tintedImg.getColorModel().getRed(tintedImg.getRaster().getDataElements(i, j, null)) * (1/255F); float greenTint = (float) tintedImg.getColorModel().getGreen(tintedImg.getRaster().getDataElements(i, j, null)) * (1/255F); float blueTint = (float) tintedImg.getColorModel().getBlue(tintedImg.getRaster().getDataElements(i, j, null)) * (1/255F); float redOut = redBase * redTint; float greenOut = greenBase * greenTint; float blueOut = blueBase * blueTint; Color colorOut = new Color (redOut, greenOut, blueOut, alpha); tintedImg.setRGB(i, j, colorOut.getRGB()); } } return tintedImg; } Thank you again! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Hey again, That's good to know-- I was probably doing something wrong then. If the first method is faster, I probably do want to use that one, even if it's a bit harder to learn... Hm. Well due to some model changes, these wolves actually use a 64x64 texture, so it is double the size of the normal one. I think the problem may have been that I declared several variables within the for-loop though, now that I think back on it, so it was creating stuff every time. That combined with the number of entities may have escalated the slow-down. The current code I have for the color overlay method is this: BufferedImage tintedImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); Color color = new Color(this.entity.getTextureColor(0)[0], this.entity.getTextureColor(0)[1], this.entity.getTextureColor(0)[2]); Graphics graphics = tintedImage.createGraphics(); graphics.setXORMode(color); graphics.drawImage(img, 0, 0, null); // NOT 'tintedImage' graphics.dispose(); return tintedImage; // Image will be tinted This has been based off recommendations I'm seeing elsewhere on the interwebs, however I think it's been for people drawing directly to the screen in a standalone application, and it doesn't seem to be returning right in my case. I'm getting what appears to be a completely transparent texture-- the entity exists in the world, but is completely invisible despite not throwing any errors. I haven't worked with any methods through OpenGL though, so if that's a faster way to go, that seems like it might be optimal. Do you have an example of that I could take a look at? In essence, what I'm trying to do is take a texture like this and apply an RGB value to it as a tint, basically as if you were using the "multiply" layer mode in an image editing program (preserving the texture of the base layer but with the new color). Then I'll have to take multiple colored layers (some with alpha transparency) and stack them, so that they blend together to make a unique marking pattern. The end result is something like this (picture from when I was using the old layer system, which had the Z fighting and/or glow issues). You can see how the white markings aren't fully opaque-- they blend into the black ones (which are on their own layer) gradually. So I need to be able to replicate that layered effect when combining my textures. I'm very new to graphical stuff, but I want to make sure I can have the most efficient solution for this so that people aren't waiting around for textures to load. If the OpenGL method would be more efficient, then if possible I think I'd like to try and figure that one out. Otherwise I'll take another crack at that for loop and see if I can get it to go a little faster this time. Thank you for the blending formula, too. That was one thing that had me really stumped! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Hey again, Thank you so much for all your help! I've got the basics of the dynamic texture working-- I got it to load my base texture file and use it as a dynamic texture. This reduces lag immensely once the texture is active-- I was able to have 200-300 entities onscreen before my frame rate hit 30fps, so I'd count that pretty reasonable even in the event that someone does want to make a dog army. However, I'm now a bit stuck as to the next step. For one thing, I need to take a grey-and-white texture (think vanilla sheep's wool) and color it. For another, I then need to repeat that process several more times, combining the textures as I go into a single BufferedImage. And I've had very little success on either account. Most of the research I've been doing has been telling me to either use for loops and iterate through the image pixel by pixel, or to use Java's Graphics to create an overlay and color the image that way. The second method has seemed like the simplest/most intuitive, but I think it may be having some issues when handling an image that's not directly being rendered to the screen (the idea is to create/manipulate the texture as a BufferedImage, and then convert that into a NativeImage which is used for the texture). The result has always been an invisible entity, which has a shadow but doesn't render onscreen at all. I could be totally off-base, but I'm thinking maybe Graphics affects specifically what you draw on the screen, and since my BufferedImage isn't actually drawn until it's saved and converted to the texture, it just... isn't working. That, or I'm just not understanding it right. The for loop method has had marginally more success-- I've gotten it to actually start working (though I couldn't figure out the equation needed to multiply the new color over the base layer so it had a limited effect), but it's extremely slow. When trying to load in my entity stress test world, I froze for 3-5 minutes while the game ran a multitude of for-loops going pixel by pixel. This was with a lot of entities, however I only tried to color the first layer-- I haven't even tried adding more. And as far as I know, the game does continue to tick in the background. Being frozen for that long would be an actual hazard, since presumably the game continues to run logic even before the screen can catch up. I want to use the most efficient method possible here, though I do greatly prefer having a lag spike once when the entity loads/updates to having one every single time the game tries to render. However, such a massive spike is definitely not what I'd prefer. I think I either need a way to tint the texture all at once, or to space out the lag spikes a little at a time. I'd rather have the texture appear unfinished (I.e. you see the uncolored base coat, then its color, then the uncolored next layer, etc.) for a little while than have the entire screen freeze for a prolonged period of time. Is there a method I could use to color/combine textures with alpha values that doesn't require me to loop through pixel by pixel? (It has occurred to me that I might be able to use the same method I use to combine textures to color them-- if I create a layer that's just a solid color and combine it with the alpha-masked base layer). If I do have to go pixel by pixel, is there a good way I can run the calculations little-by-little in the background as the rest of the game continues to render and only update the texture when each step finishes completion? Do you have any recommendations as to how I can go about this? Thank you again! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Okay, so I'm continuing on the attempt at making dynamic textures. I basically cloned the MapItemRenderer class, and reworked it to take info from one of my mod entities rather than MapData, and to draw a texture based off the entity's traits. However, now I'm not too sure how to register it. I see that MapItemRenderer is registered with this line in GameRenderer: this.mapItemRenderer = new MapItemRenderer(mcIn.getTextureManager()); I presume that I need to register my texture handler class somewhere on my end as well, but I'm not sure where that should actually go. It also looks like there are a variety of other methods there that reference it. Obviously I can't just edit that class, so how should I go about registering that code? Do I need to create an extension of GameRenderer with my own methods pertaining to my texture generator, and then register that? The only main difference between this and the MapItemRenderer class is that this just generates the textures-- and then, assuming that works, I'll just return the proper ResourceLocation for the actual entity texture from my entity renderer class... -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Ahh, I think I was trying to generate it every frame. That's likely what the problem was. I'll check on that approach again and see if I can get it to work better... that may be a lot more effective. Regarding rendering every frame, I highly suspect that's the case. My computer is pretty powerful, but I want to make the mod as accessible as possible, even for those with less powerful computers. If mine is struggling, that doesn't bode too well for those with weaker hardware, heh. I'll revisit my attempt at dynamic textures. It seems like that's probably going to be the best approach... thanks again! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Update: Running some initial framerate diagnostics this morning to get more exact numbers... Singleplayer world (7260MB memory) run through Eclipse: Normally generated world (none of my entities)- 59-60 FPS, stable One of my entities- Brief drop to 56, then back to 60 stable Five of my entities- Brief drop, then back to 60 stable Twenty-five of my entities- Brief drop, then back to 60 stable Fifty of my entities- Started dropping with around thirty entities present, stabilized out at 30fps One hundred of my entities- continued to drop, stabilized out between 10-15fps I ran /debug with 100 of my entities spawned and it said I was getting 20 ticks per second, so definitely render lag. So it does take a decent number of entities spawned for this to be an issue. However, since this mob is meant to be a pet, it's not infeasible for someone to decide to have that many of them. Is there any way I can continue to reduce this lag, or is it an inherent issue with having that many alpha layers? -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Dang, that's more of a fundamental problem than I'd have liked, but it's good to know. Thank you so much for your explanation and suggestions! I've spent some time messing with the dynamic textures, but it seems like that really didn't like what I was trying to do. Spawning in one entity gave me about one frame every three seconds, so unfortunately I don't think the system likes entities a lot (as far as I can tell it's only used in Vanilla code with entities for the Ender Dragon's death animation, which doesn't have to read a texture at all and just relies on randomly generated numbers). I had better results with your other suggestion (scaling the size increase according to the player's distance), however. This works, technically! I'm not getting the Z fighting anymore, even when I have all 5 of my current layers applied. However, with five layers, the game does start chugging a bit when you have a lot of these entities spawned. It's nowhere near as bad as the lag I had with the dynamic textures, but it is noticeable, and I'd like to cut it down if possible (especially since I have a couple more layers I would like to add). This is my current render code-- is there any way I can do this in a more optimized manner so as to reduce lag? I highly suspect it's coming from the distance calculations, so I'm wondering if I can do those more efficiently... if (!wcWolf.isInvisible()) { PlayerEntity player = Minecraft.getInstance().player; float dist = wcWolf.getDistance(player); int scalemodifier = 1; GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.enableBlend(); if (wcWolf.showMerle()) { float[] afloat = wcWolf.getEumelaninColor().getColorComponentValues(wcWolf.getEuShade()); GlStateManager.color3f(afloat[0], afloat[1], afloat[2]); this.bindTexture(this.getResourceLocation(wcWolf, 0)); this.wolfmodel = new WCWolfModel<WCWolfEntity>(0.001F * scalemodifier * dist); this.getEntityModel().setModelAttributes(this.wolfmodel); this.wolfmodel.setLivingAnimations(wcWolf, limbSwing, limbSwingAmount, partialTick); this.wolfmodel.render(wcWolf, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); scalemodifier ++; } if (wcWolf.showAgouti()) { float[] afloat = wcWolf.getPhaeomelaninColor().getColorComponentValues(wcWolf.getPhaeShade()); GlStateManager.color3f(afloat[0], afloat[1], afloat[2]); this.bindTexture(this.getResourceLocation(wcWolf, 1)); this.wolfmodel = new WCWolfModel<WCWolfEntity>(0.001F * scalemodifier * dist); this.getEntityModel().setModelAttributes(this.wolfmodel); this.wolfmodel.setLivingAnimations(wcWolf, limbSwing, limbSwingAmount, partialTick); this.wolfmodel.render(wcWolf, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); scalemodifier ++; } if (wcWolf.showUrajiro()) { float[] afloat = EnumWCFurColor.OFF_WHITE.getColorComponentValues(wcWolf.getPhaeShade()); GlStateManager.color3f(afloat[0], afloat[1], afloat[2]); this.bindTexture(this.getResourceLocation(wcWolf, 2)); this.wolfmodel = new WCWolfModel<WCWolfEntity>(0.001F * scalemodifier * dist); this.getEntityModel().setModelAttributes(this.wolfmodel); this.wolfmodel.setLivingAnimations(wcWolf, limbSwing, limbSwingAmount, partialTick); this.wolfmodel.render(wcWolf, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); scalemodifier ++; } if (wcWolf.showBrindle()) { float[] afloat = wcWolf.getEumelaninColor().getColorComponentValues(wcWolf.getEuShade()); GlStateManager.color3f(afloat[0], afloat[1], afloat[2]); this.bindTexture(this.getResourceLocation(wcWolf, 3)); this.wolfmodel = new WCWolfModel<WCWolfEntity>(0.001F * scalemodifier * dist); this.getEntityModel().setModelAttributes(this.wolfmodel); this.wolfmodel.setLivingAnimations(wcWolf, limbSwing, limbSwingAmount, partialTick); this.wolfmodel.render(wcWolf, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); scalemodifier ++; } if (wcWolf.showWhite()) { float[] afloat = EnumWCFurColor.WHITE.getColorComponentValues(0); GlStateManager.color3f(afloat[0], afloat[1], afloat[2]); this.bindTexture(this.getResourceLocation(wcWolf, 4)); this.wolfmodel = new WCWolfModel<WCWolfEntity>(0.001F * scalemodifier * dist); this.getEntityModel().setModelAttributes(this.wolfmodel); this.wolfmodel.setLivingAnimations(wcWolf, limbSwing, limbSwingAmount, partialTick); this.wolfmodel.render(wcWolf, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); scalemodifier ++; } GlStateManager.disableBlend(); } The checks to determine if the layer needs to be shown and the color grabbers shouldn't be the issue. At least, they worked well when everything was on its own render layer. When I had it set up like that, the game ran fine even with many entities spawned, but that was when I had the issues with the z fighting. Thank you again for your help! -
[1.14.4] Z fighting issues with semi-transparent entity layers
JayZX535 replied to JayZX535's topic in Modder Support
Bump. Still struggling with this. If y'all know of any good guides on GL11 that'd also be good too. It's one of the things I'm less versed in, so learning more about it def couldn't hurt.