Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[1.16.4] 2 Questions about Gui Screens and Buttons


Recommended Posts

Hi, I have 2 questions:

1. How do i get a gui screen to update instantly? My screens only update when I open/close them, or change the size of the Minecraft window. My in game gui updates instantly, which is what I want my screens to do aswell.

2. I have buttons on this gui that I want to, when hovered over, to display a string/tooltip. There is an ITooltip parameter in the constructor of the Button class, but I'm not sure what to put in there if I just want to display a string. How would I do that?

Thanks.

Link to post
Share on other sites
40 minutes ago, LK1905 said:

How do i get a gui screen to update instantly? My screens only update when I open/close them, or change the size of the Minecraft window. My in game gui updates instantly, which is what I want my screens to do aswell.

Define "update". And show code.

 

41 minutes ago, LK1905 said:

I have buttons on this gui that I want to, when hovered over, to display a string/tooltip. There is an ITooltip parameter in the constructor of the Button class, but I'm not sure what to put in there if I just want to display a string. How would I do that?

Look at what vanilla does. Basically you need to give it an implementation of ITooltip which Minecraft will then call to render the tooltip.

Link to post
Share on other sites
Quote

Define "update". And show code.

The screen has 3 buttons, all with a "style id", which, when pressed, sends a packet to set an "active attack style", which is decided by the style id of the button pressed. The buttons are all grey, except for the button with the active style id, which is supposed to turn red, and also make the previously active button grey.

The button colours do update, but only if i close/reopen the screen. I would like it to be able to update the colours while the screen is still open.

Screen class

package lk1905.gielinorcraft.client.gui.screen;

import com.mojang.blaze3d.matrix.MatrixStack;

import lk1905.gielinorcraft.Gielinorcraft;
import lk1905.gielinorcraft.api.combat.AttackStyles;
import lk1905.gielinorcraft.api.skill.ISkills;
import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import lk1905.gielinorcraft.capability.attackstyle.IAttackStyle;
import lk1905.gielinorcraft.capability.skill.SkillCapability;
import lk1905.gielinorcraft.client.gui.widget.AttackStyleButton;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.StringTextComponent;

public class AttackStyleScreen extends Screen{

	private Minecraft mc = Minecraft.getInstance();
	private final ResourceLocation TEXTURE = new ResourceLocation(Gielinorcraft.MODID, "textures/gui/combat.png");
	private AttackStyleButton[] styleButton;
	private String[] styleName;
	
	private PlayerEntity player = Minecraft.getInstance().player;
	private ISkills skillCap = player.getCapability(SkillCapability.SKILL_CAP).orElse(null);
	private IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
	
	private final int xSize = 134;
	private final int ySize = 163;
	
	private int guiLeft;
	private int guiTop;
	
	public AttackStyleScreen() {
		super(new StringTextComponent("Combat styles"));
		styleButton = new AttackStyleButton[6];
		styleName = new String[6];
	}

	@Override
	public boolean isPauseScreen() {
		return false;
	}
	
	@Override
	public void init() {
		guiLeft = (width - xSize) / 2;
		guiTop = (height - ySize) / 2;
		
		for(int i = 0; i < 6; i++) {
			if(styleCap.getAttackStyle(i) == AttackStyles.EMPTY) {
				styleButton[i] = null;
				styleName[i] = null;
			}else {
				styleButton[0] = new AttackStyleButton((width / 2) - 57, height / 2 - 45, 0);
				styleButton[1] = new AttackStyleButton((width / 2) + 1, height / 2 - 45, 1);
				styleButton[2] = new AttackStyleButton((width / 2) - 57, height / 2 - 18, 2);
				styleButton[3] = new AttackStyleButton((width / 2) + 1, height / 2 - 18, 3);
				styleButton[4] = new AttackStyleButton((width / 2) - 57, height / 2 + 9, 4);
				styleButton[5] = new AttackStyleButton((width / 2) + 1, height / 2 + 9, 5);
				
				styleName[i] = styleCap.getStyleName(i);
			}
			if(styleButton[i] != null) {
				this.addButton(styleButton[i]);
			}
		}
	}
	
	@Override
	public void render(final MatrixStack stack, final int mouseX, final int mouseY, final float partialTicks) {
		super.render(stack, mouseX, mouseY, partialTicks);
		renderBackground(stack);
		stack.push();
		stack.scale(1F, 1F, 1F);
		mc.getTextureManager().bindTexture(TEXTURE);
		this.blit(stack, guiLeft, guiTop, 0, 0, xSize, ySize);
		drawCenteredString(stack, font, "Combat level: " + skillCap.getCombatLevel(), width / 2, (height / 2) - 70, 111111);

		for(int i = 0; i < 6; i++) {
			if(styleButton[i] != null) {
				styleButton[i].renderButton(stack, mouseX, mouseY, partialTicks);
				
				if(styleButton[i].isHovered()) {
					this.renderTooltip(stack, new StringTextComponent(styleCap.getStyleDescription(i)), mouseX, mouseY);
				}
			}
			if(styleName[i] != null) {
				drawCenteredString(stack, font, styleName[0], width / 2 - 30, height / 2 - 40, Integer.parseInt("FFFFFF", 16));
				drawCenteredString(stack, font, styleName[1], width / 2 + 29, height / 2 - 40, Integer.parseInt("FFFFFF", 16));
				drawCenteredString(stack, font, styleName[2], width / 2 - 30, height / 2 - 13, Integer.parseInt("FFFFFF", 16));
				drawCenteredString(stack, font, styleName[3], width / 2 + 29, height / 2 - 13, Integer.parseInt("FFFFFF", 16));
				drawCenteredString(stack, font, styleName[4], width / 2 - 30, height / 2 + 14, Integer.parseInt("FFFFFF", 16));
				drawCenteredString(stack, font, styleName[5], width / 2 + 29, height / 2 + 14, Integer.parseInt("FFFFFF", 16));
			}
		}
		stack.pop();
	}
}

 

Button class

package lk1905.gielinorcraft.client.gui.widget;

import lk1905.gielinorcraft.Gielinorcraft;
import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import lk1905.gielinorcraft.capability.attackstyle.IAttackStyle;
import lk1905.gielinorcraft.network.AttackStyleClientPacket;
import lk1905.gielinorcraft.network.PacketHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.widget.button.ImageButton;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;

public class AttackStyleButton extends ImageButton{
	
	private static PlayerEntity player = Minecraft.getInstance().player;
	private static IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
	
	private static int yTex = 0;
	
	public AttackStyleButton(int xIn, int yIn, int widthIn, int heightIn, int xTexStartIn, int yTexStartIn,
			int yDiffTextIn, ResourceLocation resourceLocationIn, IPressable onPressIn) {
		super(xIn, yIn, widthIn, heightIn, xTexStartIn, yTexStartIn, yDiffTextIn, resourceLocationIn, onPressIn);
	}

	public AttackStyleButton(int xIn, int yIn, int styleId) {
		this(xIn, yIn, 56, 20, 137, yTex, 0 , new ResourceLocation(Gielinorcraft.MODID, "textures/gui/combat.png"), (button) -> {
			PacketHandler.sendToServer(new AttackStyleClientPacket(styleId));
		});
		
		if(styleCap.getActiveStyleId() == styleId) {
			yTex = 23;
		}else {
			yTex = 0;
		}
	}
}

I also have another problem which I forgot to mention in the OP, but it actually sets the colour of the next button to red, instead of the button it is supposed to (e.g if button with id 0 is the active id, then button with id 1 is the one thats coloured red, not button 0).

 

Quote

Look at what vanilla does. Basically you need to give it an implementation of ITooltip which Minecraft will then call to render the tooltip.

Yea, I ended up mostly succeeding at doing this(is in above code in screen class). Although the problem is that only the last button's tooltip gets rendered. 

Link to post
Share on other sites
1 hour ago, LK1905 said:


	private static PlayerEntity player = Minecraft.getInstance().player;
	private static IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
	
	private static int yTex = 0;

 

Please learn what static means and why it is wrong to use it here.

Link to post
Share on other sites

Here is what's happening:

  • You call the first AttackStyleButton constructor (in your screen's init method).
  • AttackStyleButton.yTex is 0.
  • The AttackStyleButton constructor calls super with yTex (still 0) as a parameter.
  • The AttackStyleButton constructor adjusts the yTex field according to the current active style ID. Its own yTexStartIn will be 0 regardless (it's already set).
  • You call the second AttackStyleButton constructor (in your screen's init method).
  • AttackStyleButton.yTex is whatever the previous constructor set it to and the second AttackStyleButton will set its yTextStartIn equal to the current value of yTex.
  • The AttackStyleButton constructor adjusts the yTex field according to the current active style ID. Its own yTexStartIn will be set already and not changed by this.

When a button is clicked you send the packet to the server and the server sends a packet back. The capability is updated correctly. But the buttons you created don't look at the capability ever again once they are created - so they do not update.

What you need to do:

  • yTex should not be static. Once again: Please learn what static means. The fact that this field is static still proves that you do not know what static means. Please learn what static means.
    Please learn what static means.
  • You need to update the buttons when the capability changes.
Link to post
Share on other sites

I ended up finding a solution elsewhere for my buttons to display the updated texture on the correct button:

package lk1905.gielinorcraft.client.gui.widget;

import lk1905.gielinorcraft.Gielinorcraft;
import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import lk1905.gielinorcraft.capability.attackstyle.IAttackStyle;
import lk1905.gielinorcraft.network.PacketHandler;
import lk1905.gielinorcraft.network.attackstyle.AttackStyleClientPacket;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.widget.button.ImageButton;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;

public class AttackStyleButton extends ImageButton{
	
	private static int yTex(int slotId) {	
		Minecraft mc = Minecraft.getInstance();
		PlayerEntity player =  mc.player;
		IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
		
		if(styleCap.getActiveStyleId() == slotId) {
			return 23;
		}else {
			return 0;
		}
	}

	public AttackStyleButton(int xIn, int yIn, int slotId) {	
		super(xIn, yIn, 56, 20, 137, yTex(slotId), 0 , new ResourceLocation(Gielinorcraft.MODID, "textures/gui/combat.png"), (button) -> {
			PacketHandler.sendToServer(new AttackStyleClientPacket(slotId));
		});
	}
}

And yes, the yTex(int slotId) method is static. It doesn't work if not static, and unless you give a specific reason why it shouldn't be static, and a solution that does the above but with a non-static method, its staying static.

Quote

You need to update the buttons when the capability changes.

How do I update the buttons? Is there a method I need to run in the onPress? Or a way to detect a button being pressed in my Screen that can re-render the buttons?

Also, my tooltip method still only displays the tooltip for the last button and not any of the previous ones:

if(styleButton[i].isHovered()) {
					this.renderTooltip(stack, new StringTextComponent(styleCap.getStyleDescription(i)), mouseX, mouseY);
				}

I could just hardcode it like this for every button, but I was hoping just the above statement would be able to do it.

Link to post
Share on other sites
22 hours ago, LK1905 said:

 



private static int yTex(int slotId) {	
		Minecraft mc = Minecraft.getInstance();
		PlayerEntity player =  mc.player;
		IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
		
		if(styleCap.getActiveStyleId() == slotId) {
			return 23;
		}else {
			return 0;
		}
	}

 

The yTex is calculated upon the creation of the button, and then it will always be the same afterwards.

So you will need to listen to the change, and then replace that button (you can store the instance in a field, remove it from Screen.buttons, and update the field with a new created button). 

Edited by poopoodice
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • Hello @ChampionAsh5357, thank you for your reply! I do not use the newer version of netty directly. It's a transitive dependency of Discord4j: +--- com.discord4j:discord4j-core:3.1.3 | +--- io.projectreactor:reactor-bom:Dysprosium-SR15 | | ... | +--- com.discord4j:discord-json:1.5.6 | | ... | +--- com.discord4j:discord4j-rest:3.1.3 | | ... | | \--- com.discord4j:discord4j-common:3.1.3 | | +--- io.projectreactor:reactor-bom:Dysprosium-SR15 (*) | | +--- com.discord4j:discord-json:1.5.6 (*) | | +--- io.projectreactor.netty:reactor-netty:0.9.15.RELEASE | | | +--- io.netty:netty-codec-http:4.1.54.Final (BTW, Minecraft is using io.netty:netty-all:4.1.25.Final)   I thought those line will extend "compile" by "shadow" configuration, making "compile" inherit dependencies from "shaodw": https://github.com/tony84727/xp-tweak/blob/7f24df8f46f78840d145605db1d2cfdd988ef66b/build.gradle#L114-L117 But anyway, I tried. I added netty dependency to the buildscript and found out that ./gradlew runServer is working!🎉 (the PR) However, for intellij runs, still no luck. (I've run ./gradlew genIntellijRuns again after updating the buildscript). Starting server by IDE runs will still throw java.lang.NoSuchMethodError, indicating those runs are still using old version of netty.   I still wish I can launch server by IDE runs so I can use IDE's debug utilities.
    • now I don't know how to help you you may want to create a new topic asking for help with that   the only thing that comes to mind isthat if you're on intelliJ, check if those are actaully subdirectories and not a single directory with dots in the name (as that is a very common problem that happens when people are modding with intelliJ)
    • Yes! thank you, it works great now. One more thing though, I followed default minecraft code for the armor, but even though I have all my layers in assets/gemstones/textures/models/armor it still shows up on my character as the 'no-texture' texture.
    • Exception message: java.lang.IllegalArgumentException: Duplicate registration jade you're registering "jade" twice, I think that should be the only thing wrong oh also, your enum constants should be all uppercased (it won't cause any errors of course, but it's the standard)  
    • Sure, i played around with the code a bit and added a ".get()" to the end of the material, this removed all errors. Except its wrong because now I launch and the game crashes, yet eclipse gives me no errors. Heres my list: package djofox.gemstones.materials; import java.util.function.Supplier; import djofox.gemstones.init.ItemInit; import net.minecraft.item.IItemTier; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.LazyValue; public enum ToolMaterialList implements IItemTier { beryl(0, 131, 15.0f, 2.75f, 30, () -> { return Ingredient.of(ItemInit.beryl.get()); }), jade(2, 500, 7.0f, 2.25f, 23, () -> { return Ingredient.of(ItemInit.jade.get()); }), moissanite(2, 500, 7.0f, 2.25f, 23, () -> { return Ingredient.of(ItemInit.moissanite.get()); }), kunzite(0, 315, 12f, 0.5f, 20, () -> { return Ingredient.of(ItemInit.kunzite.get()); }), orpiment(2, 258, 10f, 0.5f, 20, () -> { return Ingredient.of(ItemInit.orpiment.get()); }), mercurySulfide(2, 1012, 5.5f, 2.0f, 14, () -> { return Ingredient.of(ItemInit.mercurySulfide.get()); }), blackDiamond(3, 2757, 8.0f, 3.0f, 2, () -> { return Ingredient.of(ItemInit.blackDiamond.get()); }), treatedCarbide(4, 2560, 10.0f, 5.0f, 2, () -> { return Ingredient.of(ItemInit.siliconCarbide.get()); }); private final int level; private final int uses; private final float speed; private final float damage; private final int enchantmentValue; private final LazyValue<Ingredient> repairIngredient; private ToolMaterialList(int p_i48458_3_, int p_i48458_4_, float p_i48458_5_, float p_i48458_6_, int p_i48458_7_, Supplier<Ingredient> p_i48458_8_) { this.level = p_i48458_3_; this.uses = p_i48458_4_; this.speed = p_i48458_5_; this.damage = p_i48458_6_; this.enchantmentValue = p_i48458_7_; this.repairIngredient = new LazyValue<>(p_i48458_8_); } public int getUses() { return this.uses; } public float getSpeed() { return this.speed; } public float getAttackDamageBonus() { return this.damage; } public int getLevel() { return this.level; } public int getEnchantmentValue() { return this.enchantmentValue; } public Ingredient getRepairIngredient() { return this.repairIngredient.get(); } } Heres my init class which causes the crash (from taking other stuff) And heres the error I get when I crash (I dont know if you need it but better safe than sorry)  
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.