Tavi007
Members-
Posts
145 -
Joined
-
Last visited
Everything posted by Tavi007
-
Thank you! This is where the itemstack got the wrong value from. I just have to change styleMap and elementMap in the attachCapabiltiesEvent to new instances and the bug is gone. @SubscribeEvent(priority = EventPriority.LOWEST) public static void attachCapabilitiesItem(final AttachCapabilitiesEvent<ItemStack> event) { ItemCombatProperties itemProperties = ElementalCombatAPI.getDefaultProperties(event.getObject()); //default values HashMap<String, Integer> styleMap = new HashMap<String, Integer>(itemProperties.getDefenseStyle()); HashMap<String, Integer> elementMap = new HashMap<String, Integer>(itemProperties.getDefenseElement()); final DefenseData defData = new DefenseData(styleMap, elementMap); event.addCapability(ID, createProvider(defData)); } My mod is supposed to be used as API, so I don't have full control over the capability data. I can't just set the data to default values + enchantment values, because the DefenseData is the sum of the default values + enchantment values + some changes from some other mod. So I have to work with differences and apply the change, whenever they happen.
-
Hello! I implemented an itemstack capability, that is working fine in survival (at least I haven't noticed anything yet). But I noticed some weird behaviour with enchanted books itemstacks and the creative inventory. I try my best to explain how the bug appears. First of I use ItemTooltipEvent to make the information of the capability visible. This does work at first. For example the turtle shell has default values, which can be seen here: Another example is the Chestplate, which does not have any default values (well it does, but they won't get displayed, because they are not 'special' like water or thunder from the turtle shell) Now the enchanted book also has different values, but this time the source is the enchantment. So the values on the book are also correct Now we are getting close to the bug. If I now move the mouse back to the chestplate, it suddendly has the same values as the enchanted book. So at some point the capability of the chestplate got filled with the data from the enchanted book. Also weird is, that when I hover back over the turtle shell, the data is still the same as before (the correct behaviour). Only the itemstacks, that hasn't had any default data, have the same information as the enchanted book. I'm absolutly buffled how this happens and I can only reset it by restarting the whole game. Switching game file or switching game mode to survival and back to creative does nothing. So yeah... I really hope someone here know what to do, cause I don't. My repository: https://github.com/Tavi007/ElementalCombat addToolTipEvent: https://github.com/Tavi007/ElementalCombat/blob/224466912125ac0dcbcd6bf1f8de72261de6b174/src/main/java/Tavi007/ElementalCombat/events/RenderEvents.java#L43
-
That was a rather easy fix. Thanks!
-
Hello! I implemented some client and server configs for my mod, but as stated above, the corresponding -client.toml and -server.toml won't get generated. It's probably some small error, that I missed. So please help me out! Config classes: https://github.com/Tavi007/ElementalCombat/tree/master/src/main/java/Tavi007/ElementalCombat/config Where I registered them: https://github.com/Tavi007/ElementalCombat/blob/master/src/main/java/Tavi007/ElementalCombat/StartupClientOnly.java https://github.com/Tavi007/ElementalCombat/blob/master/src/main/java/Tavi007/ElementalCombat/StartupCommon.java
-
How can I detect a change of enchantment properties?
Tavi007 replied to Tavi007's topic in Modder Support
After sleeping a night I found a way to detect the change. It's not really necessary to keep track of the full itemstack, but rather just its enchantment mapping. So I did that in combination with a boolean, so it won't check over and over again. So yeah, no need for a new event hook. -
How can I detect a change of enchantment properties?
Tavi007 replied to Tavi007's topic in Modder Support
I'm not sure, if this will solve my problem. I want to get rid of the method ElementalCombatAPI#getDefenseDataWithEnchantment, because unlike ElementalCombat#getDefenseData this only returns a copy of the capability and not a reference. If it wouldn't return a copy, it would add the enchantment data to the capability over and over. It's also important, that ElementalCombat#getDefenseData returns the reference, becuase otherwise the API would be useless. How can I achieve, that the data from the enchantments gets applied only once? -
How can I detect a change of enchantment properties?
Tavi007 replied to Tavi007's topic in Modder Support
Do you mean, I should check for the enchantments of the itemstack in the attackCapabilitiesEvent? I tried that, but last time I checked, the itemstack hasn't had any enchantments added to it yet. So EnchantmentHelper.getEnchantments(itemstack) would always return an empty map. If you were suggesting something different, then please elaborate a bit more, because I didn't understand, what you meant. -
see here for my actual problem: https://forums.minecraftforge.net/topic/92508-how-can-i-detect-a-change-of-enchantment-properties/?tab=comments#comment-426659 I was just tinkering a bit trying to understand how minecraft is handling enchantments. I honestly don't know of a usecase for this kinda event besides my own so far...
-
Hello! For my mod I need an event, that detects a change of the enchantments on an itemstack. This would include adding/removing enchantments, but also increasing a level of an enchantment. I've been working on this problem on my own forge branch, but I ran into some problems. There seems to be two methods, that writes the nbt data of an itemstack directly. These are ItemStack#addEnchantment (called by EnchantmentContainer) and EnchantmentHelper#setEnchantment (called by RepairContainer and GrindstoneContainer). These methods would be a good place for the forge event hook, because then the event would also fire, if any other mod would change the enchantments (as long as they are using these vanilla methods). However for my actual problem of detecting enchantment changes, they are not working as I hoped. Currently I have 2 new events on my branch. The first is EnchantmentAddEvent, whichs fires in ItemStack#addEnchantment. //the hook in ItemStack public void addEnchantment(Enchantment ench, int level) { net.minecraftforge.event.enchanting.EnchantmentAddEvent event = new net.minecraftforge.event.enchanting.EnchantmentAddEvent(this, ench, level); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event); ... } //the event class public class EnchantmentAddEvent extends net.minecraftforge.eventbus.api.Event { private ItemStack itemstack; private Enchantment ench; private int level; public EnchantmentAddEvent(ItemStack itemstack, Enchantment ench, int level) { this.itemstack = itemstack; this.ench = ench; this.level = level; } } This way, one could check the current enchantments on the itemstacks, because the new one hasn't be written to it. Sadly, one would also have to check, if ench can even be applied to the itemstack. Maybe It would be better to move the hook a little bit further down the line, so the enchantments are already applied to the itemstack. However then I would also have to add a variable for the old enchantment map. The second event is EnchantmentSetEvent //event hook in EnchantmentHelper public static void setEnchantments(Map<Enchantment, Integer> enchMap, ItemStack stack) { net.minecraftforge.event.enchanting.EnchantmentSetEvent event = new net.minecraftforge.event.enchanting.EnchantmentSetEvent(stack, enchMap); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event); ... } //event public class EnchantmentSetEvent extends net.minecraftforge.eventbus.api.Event { @Nonnull private final ItemStack itemstack; private final Map<Enchantment, Integer> enchMap; public EnchantmentSetEvent(ItemStack itemstack, Map<Enchantment, Integer> enchMap) { this.itemstack = itemstack; Map<Enchantment, Integer> enchMapStack = EnchantmentHelper.getEnchantments(itemstack); this.enchMap = enchMap; } public ItemStack getItemStack() { return this.itemstack; } public Map<Enchantment, Integer> getEnchantments() { return enchMap; } } I noticed, that the setEnchantment method is called multiple times both on client and on server side (for both container) and I don't really get why this is happenning. Currently I'm also missing a hook, that detects, if an enchantment gets removed. Looking at GrindstoneContainer#removeEnchantments I noticed, that enchantments can be removed, by deleting the childTag "Enchantments" (or "StorredEnchantments"). So I supposed I would have to add another hook in ItemStack#removeChildTag (together with checking the tag), right? Is it okay, if the patch includes an if statement? To summerize: I want an event, that is essentially LivingEquipmentChangeEvent, but for ItemStacks. So the event would have 'Map<Enchantment, Integer> before' and 'Map<Enchantment, Integer> after' and the corresponding itemstack. This Event should then be fired, whenever the enchantment data of any ItemStack changes. Am I on the right track or should I tackle the problem completly differently?
-
How can I detect a change of enchantment properties?
Tavi007 replied to Tavi007's topic in Modder Support
PR stands for pull request, right? I don't have a problem with creating a new event hook, but I would have to learn how to do it. ^^" Are there any 'rules', that should be followed? -
Hi! So I've been scraching my head a lot on how I could solve my problem. I have a capability for itemstacks, that is called defenseData and which is supposed to be used not only by me, but also by other devs (it's part of my API). Now my mod also uses enchantments to interact with the defense capability. For example if an armor piece has the fire protection enchantment, the capability should get the mapping "fire":factor, with factor being a calculated integer value. If the item already has fire reduction (i.e. it has it as base value), then the factor of the enchantment should be added to the base value. Now I want to change the data in the capability, whenever a change of the enchantment happens in any form. This includes enchanting, disenchanting and also combing enchantments on an anvil. There is probably a lot more occasion, if we include other mods, which I would like to detect aswell. So how could I detect such a thing? Alternatively I thought about adding the enchantment value, whenever the capability gets attached to the itemstack. However this will result in incorrect data, because then the enchantment data will also be added, if I move the stack in the inventory. In an attempt to solve this issue I added another capability, called areEnchantmentsApplied (a boolean with default value false), which is turned to true, after adding the enchantment data for the first time (even if there weren't any). Sadly this wasn't not working as indented, because the newly enchanted itemstack uses the same capability data from it's origin (rightfully tho), which means that the enchantment data never gets added to the new itemstack, because areEnchantmentsApplied was already true. It did however solve the issue with moving items in the inventory. Currently I'm cheating my own system by getting a copy of the itemstack capability and adding the enchantment data onto it. It works, but that's not how I intented my API to work. Here you can see my current code. Any help is much appreciated.
-
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
Got it. I added the if statement if(event.getType().equals(RenderGameOverlayEvent.ElementType.HOTBAR)) { ... } and that worked for me. I hope, this is correct. -
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
Thanks to your help I got it working I read the code and got an idea, what each variable does and then confirmed my assumption by playing around with the value. This way I deobfuscated most of them myself. For anyone wondering here is the important code: @SubscribeEvent public static void displayDefenseData(RenderGameOverlayEvent.Post event) { if(Configuration.enabled()) { // see Screen#renderToolTips in client.gui.screen Minecraft mc = Minecraft.getInstance(); if(mc.player != null) { DefenseData defData = ElementalCombatAPI.getDefenseData(mc.player); if (!defData.isEmpty()) { HashMap<String, Integer> styleMap = defData.getStyleFactor(); HashMap<String, Integer> elementMap = defData.getElementFactor(); List<ITextComponent> list = new ArrayList<ITextComponent>(); list.add(new StringTextComponent("Defense:")); list.addAll(toDisplayText(styleMap)); list.addAll(toDisplayText(elementMap)); if (!list.isEmpty()) { MatrixStack matrixStack = event.getMatrixStack(); float scale = (float) Configuration.scale(); matrixStack.scale(scale, scale, scale); List<? extends IReorderingProcessor> orderedList = Lists.transform(list, ITextComponent::func_241878_f); // computes the width of the widest line. int listWidth = 0; for(IReorderingProcessor ireorderingprocessor : orderedList) { int textWidth = mc.fontRenderer.func_243245_a(ireorderingprocessor); listWidth = Math.max(textWidth, listWidth); } // computes the height of the list int listHeight = 8; if (orderedList.size() > 1) { listHeight += 2 + (orderedList.size() - 1) * (mc.fontRenderer.FONT_HEIGHT+1); } // moves the coords so the text and box appear correct int posX = 12; int posY = 12; if(!Configuration.isTop()) { int screenHeight = event.getWindow().getScaledHeight(); posY = Math.max(12, screenHeight - listHeight - 12); } if(!Configuration.isLeft()) { int screenWidth = event.getWindow().getScaledWidth(); posX = Math.max(12, screenWidth - listWidth - 12); } // draw background box matrixStack.push(); int l = -267386864; int i1 = 1347420415; int j1 = 1344798847; int k1 = 400; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR); Matrix4f matrix4f = matrixStack.getLast().getMatrix(); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY - 4, posX + listWidth + 3, posY - 3, 400, -267386864, -267386864); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY + listHeight + 3, posX + listWidth + 3, posY + listHeight + 4, 400, -267386864, -267386864); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY - 3, posX + listWidth + 3, posY + listHeight + 3, 400, -267386864, -267386864); func_238462_a_(matrix4f, bufferbuilder, posX - 4, posY - 3, posX - 3, posY + listHeight + 3, 400, -267386864, -267386864); func_238462_a_(matrix4f, bufferbuilder, posX + listWidth + 3, posY - 3, posX + listWidth + 4, posY + listHeight + 3, 400, -267386864, -267386864); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY - 3 + 1, posX - 3 + 1, posY + listHeight + 3 - 1, 400, 1347420415, 1344798847); func_238462_a_(matrix4f, bufferbuilder, posX + listWidth + 2, posY - 3 + 1, posX + listWidth + 3, posY + listHeight + 3 - 1, 400, 1347420415, 1344798847); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY - 3, posX + listWidth + 3, posY - 3 + 1, 400, 1347420415, 1347420415); func_238462_a_(matrix4f, bufferbuilder, posX - 3, posY + listHeight + 2, posX + listWidth + 3, posY + listHeight + 3, 400, 1344798847, 1344798847); RenderSystem.enableDepthTest(); RenderSystem.disableTexture(); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); RenderSystem.shadeModel(7425); bufferbuilder.finishDrawing(); WorldVertexBufferUploader.draw(bufferbuilder); RenderSystem.shadeModel(7424); RenderSystem.disableBlend(); RenderSystem.enableTexture(); IRenderTypeBuffer.Impl irendertypebuffer$impl = IRenderTypeBuffer.getImpl(Tessellator.getInstance().getBuffer()); matrixStack.translate(0.0D, 0.0D, 400.0D); // write the list on top of the background for(int i = 0; i < orderedList.size(); ++i) { IReorderingProcessor ireorderingprocessor1 = orderedList.get(i); if (ireorderingprocessor1 != null) { mc.fontRenderer.func_238416_a_(ireorderingprocessor1, (float)posX, (float)posY, -1, Configuration.textShadow(), matrix4f, irendertypebuffer$impl, false, 0, 15728880); } // first line is caption. add a little bit space to the next line if (i == 0) { posY += 2; } //next line posY += 10; } irendertypebuffer$impl.finish(); matrixStack.pop(); } } } } } Now I have one last thing, that is bugging me and I don't know what the cause of it is. When my defenseData gets rendered the toolbar gets slightly darker. I made some screenshots, that hopefully explains what I mean. without defenseData: with defenseData: Do you know or have an idea, why this happens? -
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
I know and I'm trying my best. But a lot is obfuscated and therefore hard to read. -
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
Ah, I just missunderstood you. This does make much more sense. So basically I'll have to copy and paste the code and adjust it for my case. Seems like a lot of trial and error, but if it works in the end, I'll be happy. -
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
Thanks for your answeres. Reading all that half obfuscated code is hurting my brain. Is the code in IngameGui (or Screen) less obfuscated in the newer forge versions? Otherwise this will be a lot of pain... Anyway please help me understanding the class. Im currently looking at the code, that renders scoreboards and tooltips. To render scoreboards the function AbstractGui#func_238467_a_ is used (see lines 674-688 in IngameGui), while for tooltips AbstractGui#func_238462_a_ is used (see lines 173-180 in Screen) + some RenderSystem stuff. In both cases I don't understand the AbstractGui functions, because they are completly obfuscated. Why shouldn't I subscribe to the event? I though, that it is necessary, because otherwise my code would never be called. By the way here is my repository (or rather my RenderEvent class) https://github.com/Tavi007/ElementalCombat/blob/master/src/main/java/Tavi007/ElementalCombat/events/RenderEvents.java -
Which class handles the rendering of a tooltip?
Tavi007 replied to Tavi007's topic in Modder Support
That helped already a lot. Thank you! I found the renderToolTip function in the Screen-class, but I'm using func_243308_b (which will call renderTooTip later on) instead, because all I really need is to define a list of ITextComponents. Now I want to display my list all the time (when I'm ingame) and not only when I'm looking at a container, but Minecraft#currentScreen is null, when the player is not looking at an inventory. So how can I draw directly on the game screen like the hunger bar? PS: I'm using RenderGameOverlayEvent, which should be the correct one, I think. -
Hello, I want to display some text in the same fashion as tooltips, which is why I'm searching for the corresponding vanilla class (I do not want to create a tooltip. I just want to display a text with the same background starting from a given (x,y)-position). However I was not able to find it so far and I'm hoping, that someone knows, where I have to look. So far I searched in the package minecraft.client.gui or minecraft.client.renderer, but they are huge and I hope, that I don't have to check every file...
-
[1.16.2] Text written on screen is vertical instead of horizontal
Tavi007 replied to Tavi007's topic in Modder Support
I ended up with computing the position every time. Mostly because I don't want to read the obfuscated mess, that FontRenderer currently is. 😅 Here is my working code, that displays the text starting from (posX, posY). package Tavi007.ElementalCombat.events; import java.util.HashMap; import com.mojang.blaze3d.matrix.MatrixStack; import Tavi007.ElementalCombat.Configuration; import Tavi007.ElementalCombat.ElementalCombat; import Tavi007.ElementalCombat.ElementalCombatAPI; import Tavi007.ElementalCombat.capabilities.defense.DefenseData; import Tavi007.ElementalCombat.util.DefenseDataHelper; import net.minecraft.client.Minecraft; import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; @Mod.EventBusSubscriber(modid = ElementalCombat.MOD_ID, bus = Bus.FORGE) public class DisplayDefenseData { @SubscribeEvent public static void onRenderGameOverlay(RenderGameOverlayEvent.Text event) { Minecraft mc = Minecraft.getInstance(); if(mc.player != null) { DefenseData defData = ElementalCombatAPI.getDefenseData(mc.player); HashMap<String, Integer> styleMap = defData.getStyleFactor(); HashMap<String, Integer> elementMap = defData.getElementFactor(); MatrixStack matrixStack = event.getMatrixStack(); float scale = (float) Configuration.scale(); matrixStack.scale(scale, scale, scale); float posX = Configuration.posX(); float posY = Configuration.posY(); float textHeight = mc.fontRenderer.FONT_HEIGHT; displayMap(styleMap, matrixStack, posX, posY); displayMap(elementMap, matrixStack, posX, posY + styleMap.size()*textHeight); } } private static void displayMap(HashMap<String, Integer> map, MatrixStack matrixStack, float posX, float posY) { Minecraft mc = Minecraft.getInstance(); float textHeight = mc.fontRenderer.FONT_HEIGHT; final int[] i = {0}; map.forEach ( (key, factor) -> { mc.fontRenderer.func_243248_b(matrixStack, new StringTextComponent(DefenseDataHelper.toPercentageString(key, factor)), posX, posY + i[0]*textHeight, Integer.MAX_VALUE); i[0] += 1; }); } } If you have any idea, how I could improve my code, please tell me. I'm quite happy with the result so far, tho I do wish for some background similar to tooltips for my hud. Do you have an idea, where I can read more about this topic? -
[1.16.2] Text written on screen is vertical instead of horizontal
Tavi007 replied to Tavi007's topic in Modder Support
Thank you got the text displaying correctly now, only the overlapping needs to be fixed. I tested "\n" and it didn't work. Do StringTextComponent support anything similar for creating a new line? Computing new coords for each line will work, but I would like to know, if there are other options, that I'm not aware of. -
[1.16.2] Text written on screen is vertical instead of horizontal
Tavi007 replied to Tavi007's topic in Modder Support
Thanks for your reply. Can you please elaborate, what the different input parameters from function func_243246_a do? For example I have no idea, what I'm supposed to do with the MatrixStack (or what it even does). -
Hello folks, I want to make some HUD components (some text on the screen) for my mod. My code so far looks like this: @Mod.EventBusSubscriber(modid = ElementalCombat.MOD_ID, bus = Bus.FORGE) public class DisplayDefenseData { @SubscribeEvent public static void onRenderGameOverlay(RenderGameOverlayEvent.Text event) { Minecraft mc = Minecraft.getInstance(); if(mc.player != null) { DefenseData defData = ElementalCombatAPI.getDefenseData(mc.player); HashMap<String, Integer> styleMap = defData.getStyleFactor(); HashMap<String, Integer> elementMap = defData.getElementFactor(); double scale = Configuration.scale(); //RenderSystem.scaled(scale, scale, scale); styleMap.forEach((key, factor) -> { mc.fontRenderer.func_238418_a_(new StringTextComponent(DefenseDataHelper.toPercentageString(key, factor)), Configuration.posX(), Configuration.posY(), 0x000000, Integer.MAX_VALUE); }); elementMap.forEach((key, factor) -> { mc.fontRenderer.func_238418_a_(new StringTextComponent(DefenseDataHelper.toPercentageString(key, factor)), Configuration.posX(), Configuration.posY(), 0x000000, Integer.MAX_VALUE); }); } } } The RenderSystem.scaled(...) was from my testing, because I also want to be able to scale the text. This code does actually display the information, sadly the text is only vertical and overlaps. I know, that the overlapping part can be fixed by adding a value to the x- and y-position (or does '\n' in the StringTextComponent result in a new line?). My main problem is the vertically written text. Anyone know, what I can do to write horizontal?
-
Sadly not, because I attach the same capability to entities aswell. Edit: Do you know how to check, if an itemstack is newish? That could possibly solve my problem too. Edit2: short follow up on my issue. I could solve it, by creating a new DefenseData, that stores the data from the enchantments. This way, it won't change the data stored in the itemstack capability, but this also means, that the DefenseData from the enchantments has to be calculated over and over again. This is a suboptimal solution of course, but for the time being it'll do the trick. I may rework my code to somehow save the additional data and only change it, whenever the itemstack changes its enchantments.
-
I noticed the problem, when I picked up an item in any inventory. But your guess seems to be right, cause I forgot to add the boolean in the readNBT/writeNBT methods. This at least fixed the initial bug, but now I have a new problem, that I didn't noticed before. When I enchant an item using an enchanted book and an anvil, the new itemstack in the right most slot seems to use the nbt data from the base itemstack (the left most slot). Which in my case means, that the new item has 'areEnchantmentsApplied' already set to to true, without actually checking the enchantments. What I want is, that every itemstack checks for enchantments once and sets the maps accordingly. An other solution would be to check the enchantments everytime the capability is called, but since the enchantments don't change to often, that would be inefficient. What can I do?
-
Hello! I got some weird bug with my capability, so please take a look at my repository: https://github.com/Tavi007/ElementalCombat In DefenseData I have the boolean 'areEnchantmentsApplied', which is usually set to false and changes to true, after checking for any enchantment on an item (see here and here). Once set to true, it should never change back to false. This capability also includes two maps, which changes a lot throughout the whole mod. While these maps saves their data correctly, the boolean does not. This means, that the enchantments are getting applied over and over, whenever I call the capability (which results in incorrect data in the maps). Why does the boolean not save, that it has been turned to true, while the maps are saving their data just fine? Best regards, Tavi007