Jump to content

[1.12.2] [Solved!] How to detect what’s in the player’s hand and drawing an overlay


Recommended Posts

Posted (edited)

So I’m trying to show a hud when the player is holding a certain item, but I don’t know how to achieve this

Attempt 1:

I thought of  having the hud render only if the player’s held item is the same as the instance of the item that was registered. Using ItemStack#areItemsEqual (I don’t have it in front of me rn so I’m going off memory). But i don’t know how to get an instance of the player to test it. Also would I need packets? Is the test run on the client side since it is an event dependent on the player

Edited by GooberGunter
Posted
37 minutes ago, diesieben07 said:

you can use Minecraft::player to get the player.

I’ve seen this notation before but I’m not too sure what that translates to in code, what does the double colon mean?

Posted

Yeah, I'm overthinking this, I got that part working:

@SubscribeEvent
	public static void onRenderGui(RenderGameOverlayEvent.Post e) {
		Minecraft mc = Minecraft.getMinecraft();
		if(ItemStack.areItemsEqual(mc.player.getHeldItem(EnumHand.OFF_HAND), ModItems.arcanometer.getDefaultInstance())) {
			new GuiArcanometer();
		}
	}

and I've tested it with a logger, but I think there's a problem with the line new GuiArcanometer(); because it's not showing up. And I understand everything up until this point.

Gui Class:

Spoiler

package com.GooberGunter.GrandSorcery.client.hud;

import com.GooberGunter.GrandSorcery.GSReferences;
import com.GooberGunter.GrandSorcery.common.utils.Util;

import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.ResourceLocation;

public class GuiArcanometer extends GuiScreen{
	int xSize;
	int ySize;
	
	public GuiArcanometer() {
		this.xSize=32;
		this.ySize=64;
	}
	
	@Override
	public void drawScreen(int mouseX, int mouseY, float partialTicks) {
		this.drawDefaultBackground();
		this.mc.getTextureManager().bindTexture(new ResourceLocation(GSReferences.MODID+":textures/gui/arcanometer.png"));
		this.drawModalRectWithCustomSizedTexture(this.width-this.xSize, this.height-this.ySize, this.xSize, this.ySize, this.xSize, this.ySize, this.xSize, this.ySize);
		Util.logger.info("printed");
		super.drawScreen(mouseX, mouseY, partialTicks);
	}
	
	
	@Override
	public boolean doesGuiPauseGame() {
		return false;
	}
	
	
}

 

 

Posted (edited)

So, it seems that GuiScreen is treating the overlay as an actual gui, exposing the mouse. Am I using the wrong class?

 

Edit: Ok, so it seems that I need to extend Gui not GuiScreen and I need to use the event to actually draw things with GL

Edited by GooberGunter
Posted

So I looked at some more examples and I managed this:

GuiArcana:

Spoiler

package com.GooberGunter.GrandSorcery.client.hud;

import com.GooberGunter.GrandSorcery.GSReferences;
import com.GooberGunter.GrandSorcery.common.items.ModItems;
import com.GooberGunter.GrandSorcery.common.utils.Util;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

@Mod.EventBusSubscriber
public class GuiArcanometer extends Gui{
	static int xSize;
	static int ySize;
	static Minecraft mc;
	
	public GuiArcanometer(Minecraft mc) {
		this.xSize=32;
		this.ySize=64;
		this.mc = mc;
	}
	
	
	@SubscribeEvent
	public static void renderHud(RenderGameOverlayEvent.Post e) {
		mc = Minecraft.getMinecraft();
		
		if(ItemStack.areItemsEqual(mc.player.getHeldItem(EnumHand.OFF_HAND), ModItems.arcanometer.getDefaultInstance())) {
			if(e.getType() != ElementType.EXPERIENCE) {
				Util.logger.info("nope: "+e.getType());
				return;
			}
			Util.logger.info("test");
			GlStateManager.pushAttrib();
			GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
			GlStateManager.disableLighting();
			// alpha test and blend needed due to vanilla or Forge rendering bug
			GlStateManager.enableAlpha();
			GlStateManager.enableBlend();
			mc.getTextureManager().bindTexture(new ResourceLocation(GSReferences.MODID+":textures/gui/arcanometer.png"));
			drawModalRectWithCustomSizedTexture(mc.displayWidth-xSize, 0, xSize, ySize, xSize, ySize, xSize, ySize);
			GlStateManager.popAttrib();
		}
	}
	
	
}

 

The problem I'm having now is that it's not drawing

Posted

"this" and the "mc" field were old code that I hadn't cleared out, I've simplified the class to this:

Spoiler

package com.GooberGunter.GrandSorcery.client.hud;

import com.GooberGunter.GrandSorcery.GSReferences;
import com.GooberGunter.GrandSorcery.common.items.ModItems;
import com.GooberGunter.GrandSorcery.common.utils.Util;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

@Mod.EventBusSubscriber
public class GuiArcanometer extends Gui{
	static int xSize;
	static int ySize;
	
	@SubscribeEvent
	public static void renderHud(RenderGameOverlayEvent.Post e) {
		Minecraft mc = Minecraft.getMinecraft();
		
		if(ItemStack.areItemsEqual(mc.player.getHeldItem(EnumHand.OFF_HAND), ModItems.arcanometer.getDefaultInstance())) {
			if(e.getType() != ElementType.EXPERIENCE) {
				//Util.logger.info("nope: "+e.getType());
				return;
			}
			Util.logger.info("test");
			mc.getTextureManager().bindTexture(new ResourceLocation(GSReferences.MODID+":textures/gui/arcanometer.png"));
			drawModalRectWithCustomSizedTexture(mc.displayWidth-64, 0, 64, 32, 64, 32, 64, 32);
		}
	}
	
	
}

 

 

the if statements are working, the logger displaying "test" is being executed the the next two lines are not showing any signs of execution. I've gotten no errors about the resource location, and nothing is being displayed.

Posted (edited)

what's the easiest way to accomplish that?

 

Somehow, I missed the "choose files" and spent the next hour trying to upload my source code to github (I've been meaning to do it anyway), which was a fun labyrinthine experience, only to get a small version of the picture, then I saw the attachment option. 

Edited by GooberGunter
Posted (edited)

So something is wrong with using Minecraft.getminecraft().displaywidth, causing it not to render

originally I had x=mc.displaywidth-(picture width) and it didn't work, when I replaced it with 0, it worked

 

it might have something to do with the event being static but something tells me that's not the problem

 

From what I can tell: Minecraft::displayWidth isn't the width in terms of pixels which is what the GUI goes off of, but some other unit. So if I had the length of a pixel on screen I could theoretically get the display width in terms of pixels but I'm sure there's an easier way

Edited by GooberGunter
Posted (edited)

The problem here is that the event has to be static in order to be registered, which greatly limits options here for things like drawing a string on the gui since that method is not static in the GUI class, or get the actual display width that is compatible with the Gui. I always see source code where the event isn't static, but every time I've done that it doesn't work so it's not really an option

 

...Unless, of course, I'm missing something

Edited by GooberGunter
Posted (edited)
31 minutes ago, diesieben07 said:

Not sure what you are talking about with the "static" stuff.

What I meant was that you can’t make static references to non static fields or methods, it gives an error in the IDE. I tried to get the GUI scale from GuiScreen but since it’s not static I got an error. And that the event method has to be static for the event bus to register, unless the old registering method still works

Edited by GooberGunter
Posted (edited)

Oh, I changed it from a GuiScreen to a Gui because while the png would load, it would also expose the mouse and I couldn’t find the method to disable it. MouseHandler looked kind of promising but I only looked into it a little bit 

 

Edit: so I guess I have one question

 

Would I extend GUI or GuiScreen for a game overlay?

 

Edited by GooberGunter
Posted
Just now, GooberGunter said:

Ok, so I have a class that subscribes to a RenderGameOverlayEvent, which I’ve had. And if I don’t extend a GUI class, how to I draw the png along with 5 integers on the display?

The rendering events are already in a GL11 rendering mode/matrix so you can use GL11 and related helper classes (like 
GlStateManager) to draw on the screen. You can look at the code for GUI draw methods to get ideas on what to do, or look for tutorials on making HUD mods. The RenderGameOverlayEvent is fired inside the GuiIngameForge#renderOverlay() method.

 

The reason why you want to use the correct render event is that they are fired in certain orders and if you draw in the wrong one then it will be drawn under other things that are drawn (and you might not even then see what you've drawn).

 

You can also do your own GUI, but I think for overlay it would require substituting your own version of the ingame GUI which in my opinion could be potentially less compatible with other mods.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)

Ok, thanks for clearing that up

 

So I checked the source code of some of the vanilla overlays and managed to get the overlay where I wanted, but I did my own gui:

Spoiler

@Mod.EventBusSubscriber
public class GuiArcanometer extends Gui{
	
	public static void render(Minecraft mc) {
		
		ScaledResolution scaledresolution = new ScaledResolution(mc);
		mc.getTextureManager().bindTexture(new ResourceLocation(GSReferences.MODID+":textures/gui/arcanometer.png"));
 		drawModalRectWithCustomSizedTexture(scaledresolution.getScaledWidth()-64, 0, 64, 32, 64, 32, 64, 32);
	}
	
	@SubscribeEvent
	public static void renderHud(RenderGameOverlayEvent.Post e) {
		Minecraft mc = Minecraft.getMinecraft();
		
		if(ItemStack.areItemsEqual(mc.player.getHeldItem(EnumHand.OFF_HAND), ModItems.arcanometer.getDefaultInstance())) {
			if(e.getType() != ElementType.EXPERIENCE) {return;}
			render(mc);
			Util.logger.info("Width: "+mc.displayWidth+" Height: "+mc.displayHeight);
		}
	}
	
	
}

 

 

1 hour ago, jabelar said:

You can also do your own GUI, but I think for overlay it would require substituting your own version of the ingame GUI which in my opinion could be potentially less compatible with other mods.

 If I use the Gl helper classes to draw in one location, couldn't another mod draw over it anyway or vice versa? What's the best way to ensure some level of compatibility?

 

 

Edited by GooberGunter
Posted
1 hour ago, GooberGunter said:

Ok, thanks for clearing that up

 

So I checked the source code of some of the vanilla overlays and managed to get the overlay where I wanted, but I did my own gui:

  Reveal hidden contents


@Mod.EventBusSubscriber
public class GuiArcanometer extends Gui{
	
	public static void render(Minecraft mc) {
		
		ScaledResolution scaledresolution = new ScaledResolution(mc);
		mc.getTextureManager().bindTexture(new ResourceLocation(GSReferences.MODID+":textures/gui/arcanometer.png"));
 		drawModalRectWithCustomSizedTexture(scaledresolution.getScaledWidth()-64, 0, 64, 32, 64, 32, 64, 32);
	}
	
	@SubscribeEvent
	public static void renderHud(RenderGameOverlayEvent.Post e) {
		Minecraft mc = Minecraft.getMinecraft();
		
		if(ItemStack.areItemsEqual(mc.player.getHeldItem(EnumHand.OFF_HAND), ModItems.arcanometer.getDefaultInstance())) {
			if(e.getType() != ElementType.EXPERIENCE) {return;}
			render(mc);
			Util.logger.info("Width: "+mc.displayWidth+" Height: "+mc.displayHeight);
		}
	}
	
	
}

 

 

 If I use the Gl helper classes to draw in one location, couldn't another mod draw over it anyway or vice versa? What's the best way to ensure some level of compatibility?

 

 

Well the way you're using the GUI class isn't exactly the way GUI are generally used. For example usually they are opened explicitly and have a drawing update. You're just using it to have some helper classes, which is fine, but not the same as actually opening a GUI where you do your code within the screen update methods.

 

There are different types of incompatibility. You can't avoid some other mod wanting to draw over top of your stuff, but you can do things to avoid the other mod from preventing your stuff from being drawn. For example, if you chose to make your own custom ingame GUI that extends and replaces the forge one then if someone else used the same technique then they would end up replacing yours (or you'd replace theirs depending on the order the mods load). However, if you both handle the overlay event then both of you will get to draw what you want.

 

Do you see the difference? -- if you're replacing something then there is more chance of conflict. If you're adding something there is less chance.

  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted
26 minutes ago, jabelar said:

For example, if you chose to make your own custom ingame GUI that extends and replaces the forge one then if someone else used the same technique then they would end up replacing yours (or you'd replace theirs depending on the order the mods load).

Ok. I'm planning on having the overlay draw 5 integers read from a chunk capability, on top of a .png, which will require updates, would I then use ITickable and GL helper methods to avoid using a gui? Or is this not a case where extending gui will result in a greater chance of incompatibility

Posted (edited)
3 minutes ago, GooberGunter said:

Ok. I'm planning on having the overlay draw 5 integers read from a chunk capability, on top of a .png, which will require updates, would I then use ITickable and GL helper methods to avoid using a gui? Or is this not a case where extending gui will result in a greater chance of incompatibility

extending gui is fine the way you're doing it because you're not replacing any gui.  My point was that one way people might do HUD is to actually replace the existing one, possibly extending it depending on how different they want to make it. You're not replacing a GUI so it is fine.

Edited by jabelar
  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

Announcements



×
×
  • Create New...

Important Information

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