I'm trying to find an event hook for my onEnchantment method, but I don't see one anywhere. How would you create an achievement for placing a certain enchantment on any book or item? Placing any enchantment on a certain item?
I don't know that there is one... there are events for crafting and smelting in the cpw.mods.fml.common.gameevent package, but unless they've added one for enchanting in the newer versions of Forge (I'm still on 1060...), you'll have a hard time doing that. If you can figure a way to capture the enchantment process some way other than through the vanilla enchantment table, such as creating your own enchantment process and triggering your own hook, then it's not too hard - that's what I did with my Zelda mod: by making fairy pools involved in a lot of the item upgrades / enchanting, I was able to easily trigger achievements.
Sometimes Forge adds hooks directly into classes such as Item (we get great stuff for armorTick and many other things), so you could look in there and in ItemStack. Failing that, like above, add your own if you can, or submit an event / hook request to the Forge team.
I know it's better to override class methods but I've forgot to say that my custom flower is actually a block (3D flower) so there isn't the method on ItemUse. I'm forced to use the events, because there aren't any methods for blocks in which I can manage the right click on another block.
Another solution would be to drop an item when harvesting my flower and use the item as a "placer" for the flower. In this way I could manage the right click on the flower pot having an item equipped in the player hands instead of having a block.
Every Block has an ItemBlock - create a custom one, and there you go, you have an Item and you can override onItemUse; your solution would also work, that's what doors do (have a completely separate Item, not even an ItemBlock).
First of all I'd like to thank you for your quick reply. Secondly, I'd like to know if it's better to use the ItemBlock or an Event.
I've already used ItemBlocks to manage blocks with metadatas so in this case it would be simple but what I'd like to know is if there are some disadvantages in using events. As far as i know, I think using events could slow a little bit the game because every event is intercepted by our event listener, am I right or not?
Exactly as you said: events will fire for every single item or whatever it is that triggers that event, whereas overriding a method will ensure that the method only ever runs for your specific class. It's the difference between processing every right click in the game vs. only right-clicks with your specific Item. Always use overridden methods when possible, and only use events as a last resort; granted, as long as you don't add ridiculous code in your event listener, you will probably never notice a performance difference, but it's best to code as lightly as possible.
The Meaning of Life, the Universe, and Everything.
Join Date:
11/4/2011
Posts:
53
Minecraft:
ignat980
Member Details
What if I need to do something when 2 events happen? I want to render a line when I have the bow charged. For some reason I can only render during the RenderWorldLastEvent event, and the bow charge event is ArrowNockEvent. I actually also need ArrowLooseEvent, to stop rendering. How would I do this? When I try to put the rendering code into the ArrowNockEvent it says "The local variable tessellator may not have been initialized", but it works fine under RenderWorldLastEvent.I can't do
because the game crashes.Edit: Well under both events is says "The local variable tessellator may not have been initialized", I kinda switched to just GL11 to render, I can't figure this tesselator thing out.
Hey coolAlias, i've followed your Extended Entity properties tutorial but you left me in the dark when its about storing a certain attribute. Lets use your mana system for this example. you've made a mana system and for instance a currency system in the same ExtendedPlayer class, I don't want the mana to stay on a certain amount when you die but I want the player to keep the amount of currency they had before they died?
Thanks for posting here, and sorry to keep you waiting so long. There is an entire section in the tutorial about keeping your data persistent through death; if you have two attributes and you want one to persist and one to not, one solution would be to simply separate them into two different extended properties classes and only store the one you want when you die. Another option would be, when loading the data upon respawn, to either write an entirely new method for loadFromNBT or otherwise notify your method that you don't want to load one or more variables, but initialize them to some other value:
What if I need to do something when 2 events happen? I want to render a line when I have the bow charged. For some reason I can only render during the RenderWorldLastEvent event, and the bow charge event is ArrowNockEvent. I actually also need ArrowLooseEvent, to stop rendering. How would I do this? When I try to put the rendering code into the ArrowNockEvent it says "The local variable tessellator may not have been initialized", but it works fine under RenderWorldLastEvent.I can't do
because the game crashes.Edit: Well under both events is says "The local variable tessellator may not have been initialized", I kinda switched to just GL11 to render, I can't figure this tesselator thing out.
Alright, well first, you can't (as far as I know) put two events in the same method. If you need to render something while the player has an arrow nocked, it's probably easiest to do so from the RenderPlayerEvent and just check if the player is currently using an item and if that item is a bow.
For rendering when the arrow is released, you can use ArrowLooseEvent, but remember that rendering is only client-side, so you will need to either a) only render for the player releasing the arrow (lame), or when an arrow is loosed, from the SERVER, send a packet to all nearby players letting them know that player A just shot your awesome arrow, and handle the rendering from that packet (which got sent to all the nearby clients, including the player that shot the arrow).
As for the tessellator, for whatever reason it sometimes hasn't finished drawing when you try to access it, but you can get around this by calling tessallator.draw() before you do anything else with it.
I AM BACK! WOO, Ok. Good things and bad things to report, and no idea WHY this is happening. Let's start with the good and segway to the bad.
I got data to persist (yay) but it only persists when I exit game/log off server, when I die mana resets to 50.
I have yet to add other stats and see if this is just mana or across the board, but I will do so.
Question though, seeing as this is using the same method to save the persistent data, am I missing something incredibly obvious that is different between dying and logging out/in??
Really nice and detailed tutorial , oh by the way do u have the new packet handling tutorial not the netty one im having issues with my packets :L it causes leak my packets is actually used for ai's
Really nice and detailed tutorial , oh by the way do u have the new packet handling tutorial not the netty one im having issues with my packets :L it causes leak my packets is actually used for ai's
The Meaning of Life, the Universe, and Everything.
Join Date:
7/2/2014
Posts:
55
Minecraft:
BinaryAura
Member Details
Thanks for posting this tutorial. It can be difficult to find the tutorials that I need. However, I have a problem with the GUI for my mod. I wanted my bar with the HUD underneath the heath bar. I managed to move the health and armor up to make room for the new bar but, when I try to draw the bar the texture isn't correct. Also the chat is underneath the "bar."
/**
* GuiStamina extends GuiIngameForge to gain access to the protected Objects:
* Random() rand of GuiInGameForge and int udateCounter of GuiIngame for renderHealth()
*
* @author BinaryAura
*
*/
public class GuiStamina extends GuiIngameForge {
// Top of the first bar on the left side of the HUD, excluding the XP bar, This would be my Stamina Bar.
public static int left_height = 35;
// boolean values for easy deactivation for mod compatibility
public static boolean renderArmor = true;
public static boolean renderHealth = true;
public static boolean renderStamina = true;
private static Minecraft mc = Minecraft.getMinecraft();
private static final ResourceLocation staminaBar = new ResourceLocation("staminamod:textures/gui/stamina_bar.png");
/**
*
* @param mc
*/
public GuiStamina(Minecraft mc) {
super(mc);
}
/**
*
* @param event RenderGameOverlayEvent to invoke the method
*/
@SubscribeEvent(priority = EventPriority.NORMAL)
public void onRenderHUD(RenderGameOverlayEvent event){
// Disable Vanilla rendering for Health and Armor (Left Side Bars)
GuiIngameForge.renderHealth = false;
GuiIngameForge.renderArmor = false;
res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
int width = res.getScaledWidth();
int height = res.getScaledHeight();
// Reset left_height back to default
int left_height = 35;
// Ask if the game should render each, if so, do so
if(renderStamina) left_height = renderStamina(left_height, event, width, height);
if(renderHealth) left_height = renderHealth(left_height, event, width, height);
if(renderArmor) left_height = renderArmor(left_height, event, width, height);
}
}
}
/**
* renderArmor() copy-pasted from GuiIngameForge with a few changes:
*
* - post(ARMOR); and if(pre(ARMOR)) return; statements removed
* Forge didn't like me calling events from events from events.
* - if(pre(ARMOR)) return; replaced with if(event.isCancelable()) return;
* - left_height bug. Workaround:
* leftHeight = left_height (static) -> method -> left_height (static)= left_height (in method)
*
* @param leftHeight is a work-around for a bug with left_height
* left_height = 35 in onRenderHUD()
* left_height = ? in renderArmor()
* left_height doesn't act like it resets yet still 35 in onRenderHUD()
* Do NOT know why. Concluded it was a JDK8u5 bug
* @param event takes the event from onRenderHUD() to control when rendered (pre or post)
* @param width is the width of the window
* @param height is the height of the window
* These are for location calculation
* @return left_height, the new value to increase the height for healthboost and absorption potion effects
*/
private int renderArmor(int leftHeight, RenderGameOverlayEvent event, int width, int height){
left_height = leftHeight;
if (event.isCancelable()) return left_height;
mc.mcProfiler.startSection("armor");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
int level = ForgeHooks.getTotalArmorValue(mc.thePlayer);
for (int i = 1; level > 0 && i < 20; i += 2){
if (i < level){
drawTexturedModalRect(left, top, 34, 9, 9, 9);
} else if (i == level){
drawTexturedModalRect(left, top, 25, 9, 9, 9);
} else if (i > level){
drawTexturedModalRect(left, top, 16, 9, 9, 9);
}
left += 8;
}
left_height += 10;
/**
* renderHealth() copy-pasted from GuiIngameForge with a few changes:
*
* - post(HEALTH); and if(pre(HEALTH)) return; statements removed.
* Forge didn't like me calling events from events from events.
* - if(pre(HEALTH)) return; replaced with if(event.isCancelable()) return;
* - left_height bug. Workaround:
* leftHeight = left_height (static) -> method -> left_height (static)= left_height (in method)
*
* @param leftHeight is a work-around for a bug with left_height
* left_height = 35 in onRenderHUD()
* left_height = ? in renderHealth()
* left_height doesn't act like it resets yet still 35 in onRenderHUD()
* Do NOT know why. Concluded it was a JDK8u5 bug
* @param event takes the event from onRenderHUD() to control when rendered (pre or post)
* @param width is the width of the window
* @param height is the height of the window
* These are for location calculation
* @return left_height, the new value to increase the height for healthboost and absorption potion effects
*/
private int renderHealth(int leftHeight, RenderGameOverlayEvent event, int width, int height){
left_height = leftHeight;
bind(icons);
if (event.isCancelable()) return left_height;
mc.mcProfiler.startSection("health");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
left_height += (healthRows * rowHeight);
if (rowHeight != 10) left_height += 10 - rowHeight;
int regen = -1;
if (mc.thePlayer.isPotionActive(Potion.regeneration)){
regen = super.updateCounter % 25;
}
final int TOP = 9 * (mc.theWorld.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
final int BACKGROUND = (highlight ? 25 : 16);
int MARGIN = 16;
if (mc.thePlayer.isPotionActive(Potion.poison)) MARGIN += 36;
else if (mc.thePlayer.isPotionActive(Potion.wither)) MARGIN += 72;
float absorbRemaining = absorb;
for (int i = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F) - 1; i >= 0; --i){
int row = MathHelper.ceiling_float_int((float)(i + 1) / 10.0F) - 1;
int x = left + i % 10 * 8;
int y = top - row * rowHeight;
if (health <= 4) y += rand.nextInt(2);
if (i == regen) y -= 2;
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
if (highlight){
if (i * 2 + 1 < healthLast){
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
} else if (i * 2 + 1 == healthLast){
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
}
}
if (absorbRemaining > 0.0F){
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F){
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
}else{
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
}
absorbRemaining -= 2.0F;
} else {
if (i * 2 + 1 < health){
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
} else if (i * 2 + 1 == health){
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
}
/**
* Renders a Three-in-one bar for stamina
*
* @param leftHeight is a work around for a bug with left_height.
* left_height = 35 in onRenderHUD()
* left_height = ? 32405 or 43208
* left_height did not reset yet still 35 in onRenderHUD()
* Do NOT know why. Concluded it was a JDK8u5 bug
* @param event takes the event from onRenderHUD() to control when rendered (pre or post)
* @param width is the width of the window
* @param height is the height of the window
* These are for location calculation
* @return left_height, the new value to increase the height for healthboost and absorption potion effects
*/
private int renderStamina(int leftHeight, RenderGameOverlayEvent event, int width, int height){
bind(staminaBar);
left_height = leftHeight;
props = StaminaPlayer.get(mc.thePlayer); // Extended Properties
if(event.isCancelable()) return left_height;
if(props == null || props.getStamina() == 0) return left_height;
mc.mcProfiler.startSection("stamina");
GL11.glEnable(GL11.GL_BLEND);
if(this.mc.playerController.isNotCreative()){
int left = width / 2 - 94;
int top = height - left_height;
int barWidth = 82;
int maximumFill = (int)(props.getMaximumStamina() / props.getStamina() * barWidth); // M
int currentFill = (int)(props.getCurrentStamina() / props.getStamina() * barWidth); // C
int adrenalineFill = (int)(props.getAdrenaline() / props.getStamina() * barWidth); // A
drawTexturedModalRect(left, top, 0, 0, barWidth, 5); // Background
/**
* Calls the bindTexture() to binde the .png method to the rect drawn by the tesselator.
*
* @param location the ResourceLocation of the Texture
*/
private void bind(ResourceLocation location){
mc.getTextureManager().bindTexture(location);
}
@Binary_Aura:
RenderGameOverlayEvent has many subtypes, so unless you specify one, your code will be run for every single one. This is why I (and the original wiki guide on GuiOverlays) show to do something like this:
// also, you need to select either .Pre or .Post, otherwise your code will run TWICE for every element type
// since you need to modify the vanilla behavior of health etc., you should use the .Pre event
public void onRenderExperienceBar(RenderGameOverlayEvent.Post event) {
if (event.type != ElementType.EXPERIENCE) {
return;
}
// now the rest of the code only runs ONCE, for the ElementType.EXPERIENCE
// but you can choose whichever one suits your needs
As for the chat messages, yeah well, that's where they go... you might be able to dig around and find where the rendering of chat is done and move the position, but if I were you, I'd consider moving your bar elsewhere or just ignoring it. Check out Battlegear2 - they have a stamina bar and the project is open source.
@Dagarath:
Logging out saves the player data to NBT, and then the data is loaded when the player logs back in. This does not happen automatically when the player dies (well it does, but only partially), thus the external Map storing a temporary version of the extended properties that you force save and load upon death and respawn. Please re-read the appropriate section and all spoilers therein to get a more comprehensive explanation.
Uggh I am so bad at this. I've done so over and over and over again, my code appears to be exactly as I am told to write it yet I can't get it working.
BTW: This is in 1.6.4 even though I originally complained about problems with 1.7.2, I've decided to get it working in 1.6.4 and then use the simple network wrapper for 1.7.2 (so easy to understand)
Uggh I am so bad at this. I've done so over and over and over again, my code appears to be exactly as I am told to write it yet I can't get it working.
BTW: This is in 1.6.4 even though I originally complained about problems with 1.7.2, I've decided to get it working in 1.6.4 and then use the simple network wrapper for 1.7.2 (so easy to understand)
Well, I can only guess at what might be wrong and tell you to read it again if you don't post any code The only parts that matter are:
1. Extended properties class, specifically read/write to NBT, and save/load to Proxy
2. Proxy class (or wherever you store the NBT tags between deaths)
3. Event handler for LivingDeathEvent and EntityJoinWorldEvent
As far as getting data to persist across death, there isn't really anything different between 1.6.x and 1.7.x (unless you count the network system, but even with that, your packets can remain basically the same). In fact, you don't even need packets to get data to persist - that's just to sync the data to the client if you need for rendering or other client-sided purposes. If you are using DataWatcher for your mana, for example, you won't need to bother with any custom packets to handle your mana synchronization; all you have to do is store and load the data between death and rebirth.
/**
* Created by dagarath on 26/06/2014.
*/
public class ExtendedPlayer implements IExtendedEntityProperties
{
public final static String EXT_PROP_NAME = "ExtendedPlayer";
public static final int MANA_WATCHER = 20;
private final EntityPlayer player;
private int maxMana;
public ExtendedPlayer(EntityPlayer player)
{
this.player = player;
// Start with max mana. Every player starts with the same amount.
this.maxMana = 50;
this.player.getDataWatcher().addObject(MANA_WATCHER, this.maxMana);
}
public static final void register(EntityPlayer player)
{
player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
}
public static final ExtendedPlayer get(EntityPlayer player)
{
return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
}
@Override
public void saveNBTData(NBTTagCompound compound)
{
NBTTagCompound properties = new NBTTagCompound();
public final void syncProperties()
{
ByteArrayOutputStream bos = new ByteArrayOutputStream(8);
DataOutputStream outputStream = new DataOutputStream(bos);
// We'll write max mana first so when we set current mana client
// side, it doesn't get set to 0 (see methods below)
try {
outputStream.writeInt(this.maxMana);
} catch (Exception ex) {
ex.printStackTrace();
}
Packet250CustomPayload packet = new Packet250CustomPayload("forthedarkness", bos.toByteArray());
// We only want to send from the server to the client
if (!player.worldObj.isRemote) {
EntityPlayerMP player1 = (EntityPlayerMP) player;
PacketDispatcher.sendPacketToPlayer(packet, (Player) player1);
}
}
}
/**
* Created by dagarath on 26/06/2014.
*/
public class CommonProxy implements IGuiHandler {
private static final Map<string, nbttagcompound=""> extendedEntityData = new HashMap<string, nbttagcompound="">();
public void registerRenderers() {}
public void registerTickHandler() {}
public void registerLocalization() {}
@Override
public Object getServerGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
@Override
public Object getClientGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
/**
* Created by dagarath on 26/06/2014.
*/
public class FTDEventHandler {
@ForgeSubscribe
public void onEntityConstructing(EntityConstructing event)
{
if (event.entity instanceof EntityPlayer && ExtendedPlayer.get((EntityPlayer) event.entity) == null) {
ExtendedPlayer.register((EntityPlayer) event.entity);
}
}
@ForgeSubscribe
public void onLivingDeathEvent(LivingDeathEvent event)
{
if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer)
{
ExtendedPlayer.saveProxyData((EntityPlayer) event.entity);
}
}
public void onEntityJoinWorld(EntityJoinWorldEvent event)
{
ExtendedPlayer.loadProxyData((EntityPlayer) event.entity);
}
}
EDIT: OK, everything seems fine so I did System.out.println("...stuff..."); at every step and my EventHandler never does anything LOL...
AND after further toying I moved
@EventHandler
public void load(FMLPostInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new FTDEventHandler());
}
to
@EventHandler
public void postInitialise(FMLPostInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new FTDEventHandler());
}
I also absolutely somehow missed the @ForgeSubscribe annotation for onEntityJoinWorld... wow, how it took me this long to figure out something so simple I'll never understand, but now I get it.
Oh and for the sake of completeness, somehow I deleted the if statement in onEntityJoinWorld so once I had everything working the game would crash because it tried to cast Item to EntityPlayer... lol. All is well, Thanks again coolAlias for being soo cool and calm with me, in the end it was entirely user error lol.
Wellp, I actually found a booboo I made, No @NetworkMod, fixed that.
Some minor issues within my syncProperties();
I actually managed to find my issues by opening all spoilers and searching for sync hehe
Now since it STILL does not work, I am going to post the relevant classes in spoilers
I'm going to assume that
private static final Map<string, nbttagcompound="">
was just a formatting mistake in the editor? It should be <String, NBTTagCompound> with no equals sign or quotes.
In your LivingJoinWorldEvent, you still need to check if the world is not remote and that the entity is an instanceof EntityPlayer, just like in the LivingDeathEvent.
Other than that, everything looks as it should. What exactly is not persisting after you die? Have you printed the values of your variables to the console with println, being sure to distinguish between the value on the client and on the server? Are you sure you aren't just doing something funky with your syncProps packet? You send the max mana in the packet; when you receive the packet, do you set the current mana to equal max mana? (if you did, note that it would not really equal max mana on the server, but it might 'look' like it's max).
ellp, I actually found a booboo I made, No @NetworkMod, fixed that.
Some minor issues within my syncProperties();
I actually managed to find my issues by opening all spoilers and searching for sync hehe
Now since it STILL does not work, I am going to post the relevant classes in spoilers
I'm going to assume that
private static final Map<string, nbttagcompound="">
was just a formatting mistake in the editor? It should be with no equals sign or quotes.
In your LivingJoinWorldEvent, you still need to check if the world is not remote and that the entity is an instanceof EntityPlayer, just like in the LivingDeathEvent.
Other than that, everything looks as it should. What exactly is not persisting after you die? Have you printed the values of your variables to the console with println, being sure to distinguish between the value on the client and on the server? Are you sure you aren't just doing something funky with your syncProps packet? You send the max mana in the packet; when you receive the packet, do you set the current mana to equal max mana? (if you did, note that it would not really equal max mana on the server, but it might 'look' like it's max).
I updated my above post, I assume when you replied to me lol. I have it handled, stuff saves, all is good just making custom GUI now to display my stats hehe.
Oddly enough, yes it is <String, NBTTagCompound> but for some odd reason copy pasting it changed it lol, my code does NOT look like the spoiler.
from each of the rendering methods. The bar no longer renders on top of the chat. However, the bar is still not rendering correctly.
Below is my changed code.
public class GuiStamina extends GuiIngameForge {
// boolean values for easy deactivation for mod compatibility
public static boolean renderArmor = true;
public static boolean renderHealth = true;
public static boolean renderStamina = true;
// Top of the first bar on the left side of the HUD, excluding the XP bar, This would be my Stamina Bar.
public static int left_height = 35;
private static Minecraft mc = Minecraft.getMinecraft();
private static final ResourceLocation staminaBar = new ResourceLocation("staminamod:textures/gui/stamina_bar.png");
/**
*
* @param mc
*/
public GuiStamina(Minecraft mc) {
super(mc);
// Disable Vanilla rendering for Health and Armor (Left Side Bars)
GuiIngameForge.renderHealth = false;
GuiIngameForge.renderArmor = false;
}
/**
* renderHealth() copy-pasted from GuiIngameForge with a few changes:
*
* - post(HEALTH); and if(pre(HEALTH)) return; statements removed.
* Forge didn't like me calling events from events from events.
* - if(pre(HEALTH)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
public void renderHealth(int width, int height){
bind(icons);
mc.mcProfiler.startSection("health");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
left_height += (healthRows * rowHeight);
if (rowHeight != 10) left_height += 10 - rowHeight;
int regen = -1;
if (mc.thePlayer.isPotionActive(Potion.regeneration))
{
regen = super.updateCounter % 25;
}
final int TOP = 9 * (mc.theWorld.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
final int BACKGROUND = (highlight ? 25 : 16);
int MARGIN = 16;
if (mc.thePlayer.isPotionActive(Potion.poison)) MARGIN += 36;
else if (mc.thePlayer.isPotionActive(Potion.wither)) MARGIN += 72;
float absorbRemaining = absorb;
for (int i = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F) - 1; i >= 0; --i)
{
int row = MathHelper.ceiling_float_int((float)(i + 1) / 10.0F) - 1;
int x = left + i % 10 * 8;
int y = top - row * rowHeight;
if (health <= 4) y += rand.nextInt(2);
if (i == regen) y -= 2;
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
if (highlight)
{
if (i * 2 + 1 < healthLast){
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
}
else if (i * 2 + 1 == healthLast){
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
}
}
if (absorbRemaining > 0.0F)
{
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F){
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
}
else{
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
}
absorbRemaining -= 2.0F;
}
else
{
if (i * 2 + 1 < health){
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
}
else if (i * 2 + 1 == health){
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
}
/**
*
* @param event RenderGameOverlayEvent to invoke the method
*/
@SubscribeEvent(priority = EventPriority.NORMAL)
public void onRenderHUD(RenderGameOverlayEvent event){
// Checks to see if it is after (event.isCancelable() is false if the event is Post) the rendering of BOSSHEALTH
if(event.type != ElementType.BOSSHEALTH || event.isCancelable()) return;
res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
int width = res.getScaledWidth();
int height = res.getScaledHeight();
// Reset left_height back to default
left_height = 35;
// Ask if the game should render each, if so, do so
if(renderStamina) renderStamina(width, height);
if(renderHealth) renderHealth(width, height);
if(renderArmor) renderArmor(width, height);
}
}
}
/**
* renderArmor() copy-pasted from GuiIngameForge with a few changes:
*
* - post(ARMOR); and if(pre(ARMOR)) return; statements removed
* Forge didn't like me calling events from events from events.
* - if(pre(ARMOR)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
protected void renderArmor(int width, int height){
mc.mcProfiler.startSection("armor");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
int level = ForgeHooks.getTotalArmorValue(mc.thePlayer);
for (int i = 1; level > 0 && i < 20; i += 2)
{
if (i < level)
{
drawTexturedModalRect(left, top, 34, 9, 9, 9);
}
else if (i == level)
{
drawTexturedModalRect(left, top, 25, 9, 9, 9);
}
else if (i > level)
{
drawTexturedModalRect(left, top, 16, 9, 9, 9);
}
left += 8;
}
left_height += 10;
/**
* Renders a Three-in-one bar for stamina
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
protected void renderStamina(int width, int height){
bind(staminaBar);
props = StaminaPlayer.get(mc.thePlayer); // Extended Properties
if(props == null || props.getStamina() == 0) return; //left_height;
mc.mcProfiler.startSection("stamina");
GL11.glEnable(GL11.GL_BLEND);
if(this.mc.playerController.isNotCreative()){
int left = width / 2 - 94;
int top = height - left_height;
int barWidth = 82;
int maximumFill = (int)(props.getMaximumStamina() / props.getStamina() * barWidth); // M
int currentFill = (int)(props.getCurrentStamina() / props.getStamina() * barWidth); // C
int adrenalineFill = (int)(props.getAdrenaline() / props.getStamina() * barWidth); // A
drawTexturedModalRect(left, top, 0, 0, barWidth, 5); // Background
/**
* Calls the bindTexture() to binde the .png method to the rect drawn by the tesselator.
*
* @param location the ResourceLocation of the Texture
*/
private void bind(ResourceLocation location)
{
mc.getTextureManager().bindTexture(location);
}
from each of the rendering methods. The bar no longer renders on top of the chat. However, the bar is still not rendering correctly.
Below is my changed code.
public class GuiStamina extends GuiIngameForge {
// boolean values for easy deactivation for mod compatibility
public static boolean renderArmor = true;
public static boolean renderHealth = true;
public static boolean renderStamina = true;
// Top of the first bar on the left side of the HUD, excluding the XP bar, This would be my Stamina Bar.
public static int left_height = 35;
private static Minecraft mc = Minecraft.getMinecraft();
private static final ResourceLocation staminaBar = new ResourceLocation("staminamod:textures/gui/stamina_bar.png");
/**
*
* @param mc
*/
public GuiStamina(Minecraft mc) {
super(mc);
// Disable Vanilla rendering for Health and Armor (Left Side Bars)
GuiIngameForge.renderHealth = false;
GuiIngameForge.renderArmor = false;
}
/**
* renderHealth() copy-pasted from GuiIngameForge with a few changes:
*
* - post(HEALTH); and if(pre(HEALTH)) return; statements removed.
* Forge didn't like me calling events from events from events.
* - if(pre(HEALTH)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
public void renderHealth(int width, int height){
bind(icons);
mc.mcProfiler.startSection("health");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
left_height += (healthRows * rowHeight);
if (rowHeight != 10) left_height += 10 - rowHeight;
int regen = -1;
if (mc.thePlayer.isPotionActive(Potion.regeneration))
{
regen = super.updateCounter % 25;
}
final int TOP = 9 * (mc.theWorld.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
final int BACKGROUND = (highlight ? 25 : 16);
int MARGIN = 16;
if (mc.thePlayer.isPotionActive(Potion.poison)) MARGIN += 36;
else if (mc.thePlayer.isPotionActive(Potion.wither)) MARGIN += 72;
float absorbRemaining = absorb;
for (int i = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F) - 1; i >= 0; --i)
{
int row = MathHelper.ceiling_float_int((float)(i + 1) / 10.0F) - 1;
int x = left + i % 10 * 8;
int y = top - row * rowHeight;
if (health <= 4) y += rand.nextInt(2);
if (i == regen) y -= 2;
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
if (highlight)
{
if (i * 2 + 1 < healthLast){
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
}
else if (i * 2 + 1 == healthLast){
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
}
}
if (absorbRemaining > 0.0F)
{
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F){
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
}
else{
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
}
absorbRemaining -= 2.0F;
}
else
{
if (i * 2 + 1 < health){
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
}
else if (i * 2 + 1 == health){
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
}
/**
*
* @param event RenderGameOverlayEvent to invoke the method
*/
@SubscribeEvent(priority = EventPriority.NORMAL)
public void onRenderHUD(RenderGameOverlayEvent event){
// Checks to see if it is after (event.isCancelable() is false if the event is Post) the rendering of BOSSHEALTH
if(event.type != ElementType.BOSSHEALTH || event.isCancelable()) return;
res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
int width = res.getScaledWidth();
int height = res.getScaledHeight();
// Reset left_height back to default
left_height = 35;
// Ask if the game should render each, if so, do so
if(renderStamina) renderStamina(width, height);
if(renderHealth) renderHealth(width, height);
if(renderArmor) renderArmor(width, height);
}
}
}
/**
* renderArmor() copy-pasted from GuiIngameForge with a few changes:
*
* - post(ARMOR); and if(pre(ARMOR)) return; statements removed
* Forge didn't like me calling events from events from events.
* - if(pre(ARMOR)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
protected void renderArmor(int width, int height){
mc.mcProfiler.startSection("armor");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
int level = ForgeHooks.getTotalArmorValue(mc.thePlayer);
for (int i = 1; level > 0 && i < 20; i += 2)
{
if (i < level)
{
drawTexturedModalRect(left, top, 34, 9, 9, 9);
}
else if (i == level)
{
drawTexturedModalRect(left, top, 25, 9, 9, 9);
}
else if (i > level)
{
drawTexturedModalRect(left, top, 16, 9, 9, 9);
}
left += 8;
}
left_height += 10;
/**
* Renders a Three-in-one bar for stamina
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
protected void renderStamina(int width, int height){
bind(staminaBar);
props = StaminaPlayer.get(mc.thePlayer); // Extended Properties
if(props == null || props.getStamina() == 0) return; //left_height;
mc.mcProfiler.startSection("stamina");
GL11.glEnable(GL11.GL_BLEND);
if(this.mc.playerController.isNotCreative()){
int left = width / 2 - 94;
int top = height - left_height;
int barWidth = 82;
int maximumFill = (int)(props.getMaximumStamina() / props.getStamina() * barWidth); // M
int currentFill = (int)(props.getCurrentStamina() / props.getStamina() * barWidth); // C
int adrenalineFill = (int)(props.getAdrenaline() / props.getStamina() * barWidth); // A
drawTexturedModalRect(left, top, 0, 0, barWidth, 5); // Background
/**
* Calls the bindTexture() to binde the .png method to the rect drawn by the tesselator.
*
* @param location the ResourceLocation of the Texture
*/
private void bind(ResourceLocation location)
{
mc.getTextureManager().bindTexture(location);
}
Could you be a little more specific -> what, exactly, about the bar is not rendering correctly? Phrased another way, what do you expect to render, and what is rendering? Glad you fixed the height and chat issues, though.
I made this picture a while back to see how the bar would operate.
Attached: Stamina Example.png
And this is the concept art that is in the assets folder:
Attached: staminaBar
This is a cropped screen shot:
Specifically, since the update part of the mod isn't working yet, I'm expected to see this:
It looks like you might have multiple bars rendering over each other, or perhaps your texture is not the correct resolution. What I would do, if I were you, is try to just get a simple, solid bar to render first, without doing any of your stamina calculations - comment all that stuff out.
Another possibility is you may need to set the color before you render: GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
This way the color that you see in your texture file is the color that will render on the screen, as many of the Minecraft render functions change the openGL color settings.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI don't know that there is one... there are events for crafting and smelting in the cpw.mods.fml.common.gameevent package, but unless they've added one for enchanting in the newer versions of Forge (I'm still on 1060...), you'll have a hard time doing that. If you can figure a way to capture the enchantment process some way other than through the vanilla enchantment table, such as creating your own enchantment process and triggering your own hook, then it's not too hard - that's what I did with my Zelda mod: by making fairy pools involved in a lot of the item upgrades / enchanting, I was able to easily trigger achievements.
Sometimes Forge adds hooks directly into classes such as Item (we get great stuff for armorTick and many other things), so you could look in there and in ItemStack. Failing that, like above, add your own if you can, or submit an event / hook request to the Forge team.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumEvery Block has an ItemBlock - create a custom one, and there you go, you have an Item and you can override onItemUse; your solution would also work, that's what doors do (have a completely separate Item, not even an ItemBlock).
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumExactly as you said: events will fire for every single item or whatever it is that triggers that event, whereas overriding a method will ensure that the method only ever runs for your specific class. It's the difference between processing every right click in the game vs. only right-clicks with your specific Item. Always use overridden methods when possible, and only use events as a last resort; granted, as long as you don't add ridiculous code in your event listener, you will probably never notice a performance difference, but it's best to code as lightly as possible.
@SubscribeEventpublic void lineRender(RenderWorldLastEvent event, ArrowLooseEvent event2) {code;}because the game crashes.Edit: Well under both events is says "The local variable tessellator may not have been initialized", I kinda switched to just GL11 to render, I can't figure this tesselator thing out.-
View User Profile
-
View Posts
-
Send Message
Curse PremiumThanks for posting here, and sorry to keep you waiting so long. There is an entire section in the tutorial about keeping your data persistent through death; if you have two attributes and you want one to persist and one to not, one solution would be to simply separate them into two different extended properties classes and only store the one you want when you die. Another option would be, when loading the data upon respawn, to either write an entirely new method for loadFromNBT or otherwise notify your method that you don't want to load one or more variables, but initialize them to some other value:
public static final void loadProxyData(EntityPlayer player) { ExtendedPlayer playerData = ExtendedPlayer.get(player); NBTTagCompound savedData = CommonProxy.getEntityData(getSaveKey(player)); if (savedData != null) { // regular load: playerData.loadNBTData(savedData); playerData.selectiveLoadNBTData(savedData); } } private void selectiveLoadNBTData(NBTTagCompound compound) { gold = compound.getInteger("gold"); // mana = don't load... }Alright, well first, you can't (as far as I know) put two events in the same method. If you need to render something while the player has an arrow nocked, it's probably easiest to do so from the RenderPlayerEvent and just check if the player is currently using an item and if that item is a bow.
For rendering when the arrow is released, you can use ArrowLooseEvent, but remember that rendering is only client-side, so you will need to either a) only render for the player releasing the arrow (lame), or
As for the tessellator, for whatever reason it sometimes hasn't finished drawing when you try to access it, but you can get around this by calling tessallator.draw() before you do anything else with it.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI got data to persist (yay) but it only persists when I exit game/log off server, when I die mana resets to 50.
I have yet to add other stats and see if this is just mana or across the board, but I will do so.
Question though, seeing as this is using the same method to save the persistent data, am I missing something incredibly obvious that is different between dying and logging out/in??
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-
View User Profile
-
View Posts
-
Send Message
Curse PremiumThis tutorial Heltrato?
GUI CODE:
public class GuiStamina extends GuiIngameForge {if (absorbRemaining > 0.0F){if (absorbRemaining == absorb && absorb % 2.0F == 1.0F){
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
}else{
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
}
absorbRemaining -= 2.0F;
} else {
if (i * 2 + 1 < health){
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
} else if (i * 2 + 1 == health){
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
}
The staminaBar Texture is:
(82 p x 30 p) each bar (82 p x 5 p)
Screenshots of Testing:
The stamina"Bar":
Bar Overlapping the Chat:
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumRenderGameOverlayEvent has many subtypes, so unless you specify one, your code will be run for every single one. This is why I (and the original wiki guide on GuiOverlays) show to do something like this:
// also, you need to select either .Pre or .Post, otherwise your code will run TWICE for every element type // since you need to modify the vanilla behavior of health etc., you should use the .Pre event public void onRenderExperienceBar(RenderGameOverlayEvent.Post event) { if (event.type != ElementType.EXPERIENCE) { return; } // now the rest of the code only runs ONCE, for the ElementType.EXPERIENCE // but you can choose whichever one suits your needsAs for the chat messages, yeah well, that's where they go... you might be able to dig around and find where the rendering of chat is done and move the position, but if I were you, I'd consider moving your bar elsewhere or just ignoring it. Check out Battlegear2 - they have a stamina bar and the project is open source.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumLogging out saves the player data to NBT, and then the data is loaded when the player logs back in. This does not happen automatically when the player dies (well it does, but only partially), thus the external Map storing a temporary version of the extended properties that you force save and load upon death and respawn. Please re-read the appropriate section and all spoilers therein to get a more comprehensive explanation.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumBTW: This is in 1.6.4 even though I originally complained about problems with 1.7.2, I've decided to get it working in 1.6.4 and then use the simple network wrapper for 1.7.2 (so easy to understand)
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumWell, I can only guess at what might be wrong and tell you to read it again if you don't post any code
1. Extended properties class, specifically read/write to NBT, and save/load to Proxy
2. Proxy class (or wherever you store the NBT tags between deaths)
3. Event handler for LivingDeathEvent and EntityJoinWorldEvent
As far as getting data to persist across death, there isn't really anything different between 1.6.x and 1.7.x (unless you count the network system, but even with that, your packets can remain basically the same). In fact, you don't even need packets to get data to persist - that's just to sync the data to the client if you need for rendering or other client-sided purposes. If you are using DataWatcher for your mana, for example, you won't need to bother with any custom packets to handle your mana synchronization; all you have to do is store and load the data between death and rebirth.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumSome minor issues within my syncProperties();
I actually managed to find my issues by opening all spoilers and searching for sync hehe
Now since it STILL does not work, I am going to post the relevant classes in spoilers
ExtendedPlayer
import com.dagarath.forthedarkness.common.CommonProxy;
import cpw.mods.fml.common.network.PacketDispatcher;
import cpw.mods.fml.common.network.Player;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.packet.Packet250CustomPayload;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
/**
* Created by dagarath on 26/06/2014.
*/
public class ExtendedPlayer implements IExtendedEntityProperties
{
public final static String EXT_PROP_NAME = "ExtendedPlayer";
public static final int MANA_WATCHER = 20;
private final EntityPlayer player;
private int maxMana;
public ExtendedPlayer(EntityPlayer player)
{
this.player = player;
// Start with max mana. Every player starts with the same amount.
this.maxMana = 50;
this.player.getDataWatcher().addObject(MANA_WATCHER, this.maxMana);
}
public static final void register(EntityPlayer player)
{
player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
}
public static final ExtendedPlayer get(EntityPlayer player)
{
return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
}
@Override
public void saveNBTData(NBTTagCompound compound)
{
NBTTagCompound properties = new NBTTagCompound();
properties.setInteger("CurrentMana", this.player.getDataWatcher().getWatchableObjectInt(MANA_WATCHER));
properties.setInteger("MaxMana", this.maxMana);
compound.setTag(EXT_PROP_NAME, properties);
}
@Override
public void loadNBTData(NBTTagCompound compound)
{
NBTTagCompound properties = (NBTTagCompound) compound.getTag(EXT_PROP_NAME);
this.player.getDataWatcher().updateObject(MANA_WATCHER, properties.getInteger("CurrentMana"));
this.maxMana = properties.getInteger("MaxMana");
System.out.println("[Properties] Mana from NBT: " + properties.getInteger("CurrentMana") + "/" + this.maxMana);
}
public static String getSaveKey(EntityPlayer player)
{
return player.username + ":" + EXT_PROP_NAME;
}
public static void saveProxyData(EntityPlayer player)
{
ExtendedPlayer playerData = ExtendedPlayer.get(player);
NBTTagCompound savedData = new NBTTagCompound();
playerData.saveNBTData(savedData);
CommonProxy.storeEntityData(getSaveKey(player), savedData);
}
@Override
public void init(Entity entity, World world)
{
}
public boolean consumeMana(int amount)
{
int mana = this.player.getDataWatcher().getWatchableObjectInt(MANA_WATCHER);
boolean sufficient = amount <= mana;
mana -= (amount < mana ? amount : mana);
this.player.getDataWatcher().updateObject(MANA_WATCHER, mana);
return sufficient;
}
public final void replenishMana()
{
this.player.getDataWatcher().updateObject(MANA_WATCHER, this.maxMana);
}
public final int getCurrentMana()
{
return this.player.getDataWatcher().getWatchableObjectInt(MANA_WATCHER);
}
public final void setCurrentMana(int amount)
{
this.player.getDataWatcher().updateObject(MANA_WATCHER, (amount < this.maxMana ? amount : this.maxMana));
}
public final int getMaxMana()
{
return this.maxMana;
}
public void setMaxMana(int maxMana) {
this.maxMana = maxMana;
}
public static void loadProxyData(EntityPlayer player)
{
ExtendedPlayer playerData = ExtendedPlayer.get(player);
NBTTagCompound savedData = CommonProxy.getEntityData(getSaveKey(player));
if(savedData != null) {
playerData.loadNBTData(savedData);
}
playerData.syncProperties();
}
public final void syncProperties()
{
ByteArrayOutputStream bos = new ByteArrayOutputStream(8);
DataOutputStream outputStream = new DataOutputStream(bos);
// We'll write max mana first so when we set current mana client
// side, it doesn't get set to 0 (see methods below)
try {
outputStream.writeInt(this.maxMana);
} catch (Exception ex) {
ex.printStackTrace();
}
Packet250CustomPayload packet = new Packet250CustomPayload("forthedarkness", bos.toByteArray());
// We only want to send from the server to the client
if (!player.worldObj.isRemote) {
EntityPlayerMP player1 = (EntityPlayerMP) player;
PacketDispatcher.sendPacketToPlayer(packet, (Player) player1);
}
}
}
CommonProxy
import cpw.mods.fml.common.network.IGuiHandler;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.Map;
/**
* Created by dagarath on 26/06/2014.
*/
public class CommonProxy implements IGuiHandler {
private static final Map<string, nbttagcompound=""> extendedEntityData = new HashMap<string, nbttagcompound="">();
public void registerRenderers() {}
public void registerTickHandler() {}
public void registerLocalization() {}
@Override
public Object getServerGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
@Override
public Object getClientGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
public static void storeEntityData(String name, NBTTagCompound compound)
{
extendedEntityData.put(name, compound);
}
public static NBTTagCompound getEntityData(String name)
{
return extendedEntityData.remove(name);
}
}
ClientProxy
import com.dagarath.forthedarkness.common.CommonProxy;
import com.dagarath.forthedarkness.common.FTDTickHandler;
import cpw.mods.fml.common.registry.LanguageRegistry;
import cpw.mods.fml.common.registry.TickRegistry;
import cpw.mods.fml.relauncher.Side;
import net.minecraftforge.client.GuiIngameForge;
/**
* Created by dagarath on 26/06/2014.
*/
public class ClientProxy extends CommonProxy {
@Override
public void registerRenderers() {}
public void registerTickHandler() {
}
public void registerLocalization() {
}
}
EventHandler
import com.dagarath.forthedarkness.client.player.ExtendedPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.EntityEvent.EntityConstructing;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
/**
* Created by dagarath on 26/06/2014.
*/
public class FTDEventHandler {
@ForgeSubscribe
public void onEntityConstructing(EntityConstructing event)
{
if (event.entity instanceof EntityPlayer && ExtendedPlayer.get((EntityPlayer) event.entity) == null) {
ExtendedPlayer.register((EntityPlayer) event.entity);
}
}
@ForgeSubscribe
public void onLivingDeathEvent(LivingDeathEvent event)
{
if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer)
{
ExtendedPlayer.saveProxyData((EntityPlayer) event.entity);
}
}
public void onEntityJoinWorld(EntityJoinWorldEvent event)
{
ExtendedPlayer.loadProxyData((EntityPlayer) event.entity);
}
}
EDIT: OK, everything seems fine so I did System.out.println("...stuff..."); at every step and my EventHandler never does anything LOL...
AND after further toying I moved
@EventHandler
public void load(FMLPostInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new FTDEventHandler());
}
to
@EventHandler
public void postInitialise(FMLPostInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new FTDEventHandler());
}
I also absolutely somehow missed the @ForgeSubscribe annotation for onEntityJoinWorld... wow, how it took me this long to figure out something so simple I'll never understand, but now I get it.
Oh and for the sake of completeness, somehow I deleted the if statement in onEntityJoinWorld so once I had everything working the game would crash because it tried to cast Item to EntityPlayer... lol. All is well, Thanks again coolAlias for being soo cool and calm with me, in the end it was entirely user error lol.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI'm going to assume that
was just a formatting mistake in the editor? It should be <String, NBTTagCompound> with no equals sign or quotes.
In your LivingJoinWorldEvent, you still need to check if the world is not remote and that the entity is an instanceof EntityPlayer, just like in the LivingDeathEvent.
Other than that, everything looks as it should. What exactly is not persisting after you die? Have you printed the values of your variables to the console with println, being sure to distinguish between the value on the client and on the server? Are you sure you aren't just doing something funky with your syncProps packet? You send the max mana in the packet; when you receive the packet, do you set the current mana to equal max mana? (if you did, note that it would not really equal max mana on the server, but it might 'look' like it's max).
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI updated my above post, I assume when you replied to me lol. I have it handled, stuff saves, all is good just making custom GUI now to display my stats hehe.
Oddly enough, yes it is <String, NBTTagCompound> but for some odd reason copy pasting it changed it lol, my code does NOT look like the spoiler.
and removed
from each of the rendering methods. The bar no longer renders on top of the chat. However, the bar is still not rendering correctly.
Below is my changed code.
public class GuiStamina extends GuiIngameForge {
// boolean values for easy deactivation for mod compatibility
public static boolean renderArmor = true;
public static boolean renderHealth = true;
public static boolean renderStamina = true;
// Top of the first bar on the left side of the HUD, excluding the XP bar, This would be my Stamina Bar.
public static int left_height = 35;
private static Minecraft mc = Minecraft.getMinecraft();
private static final ResourceLocation staminaBar = new ResourceLocation("staminamod:textures/gui/stamina_bar.png");
/**
*
* @param mc
*/
public GuiStamina(Minecraft mc) {
super(mc);
// Disable Vanilla rendering for Health and Armor (Left Side Bars)
GuiIngameForge.renderHealth = false;
GuiIngameForge.renderArmor = false;
}
/**
* renderHealth() copy-pasted from GuiIngameForge with a few changes:
*
* - post(HEALTH); and if(pre(HEALTH)) return; statements removed.
* Forge didn't like me calling events from events from events.
* - if(pre(HEALTH)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
public void renderHealth(int width, int height){
bind(icons);
mc.mcProfiler.startSection("health");
GL11.glEnable(GL11.GL_BLEND);
boolean highlight = mc.thePlayer.hurtResistantTime / 3 % 2 == 1;
if (mc.thePlayer.hurtResistantTime < 10)
{
highlight = false;
}
IAttributeInstance attrMaxHealth = this.mc.thePlayer.getEntityAttribute(SharedMonsterAttributes.maxHealth);
int health = MathHelper.ceiling_float_int(mc.thePlayer.getHealth());
int healthLast = MathHelper.ceiling_float_int(mc.thePlayer.prevHealth);
float healthMax = (float)attrMaxHealth.getAttributeValue();
float absorb = this.mc.thePlayer.getAbsorptionAmount();
int healthRows = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F / 10.0F);
int rowHeight = Math.max(10 - (healthRows - 2), 3);
super.rand.setSeed((long)(super.updateCounter * 312871));
int left = width / 2 - 91;
int top = height - left_height;
left_height += (healthRows * rowHeight);
if (rowHeight != 10) left_height += 10 - rowHeight;
int regen = -1;
if (mc.thePlayer.isPotionActive(Potion.regeneration))
{
regen = super.updateCounter % 25;
}
final int TOP = 9 * (mc.theWorld.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
final int BACKGROUND = (highlight ? 25 : 16);
int MARGIN = 16;
if (mc.thePlayer.isPotionActive(Potion.poison)) MARGIN += 36;
else if (mc.thePlayer.isPotionActive(Potion.wither)) MARGIN += 72;
float absorbRemaining = absorb;
for (int i = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F) - 1; i >= 0; --i)
{
int row = MathHelper.ceiling_float_int((float)(i + 1) / 10.0F) - 1;
int x = left + i % 10 * 8;
int y = top - row * rowHeight;
if (health <= 4) y += rand.nextInt(2);
if (i == regen) y -= 2;
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
if (highlight)
{
if (i * 2 + 1 < healthLast){
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
}
else if (i * 2 + 1 == healthLast){
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
}
}
if (absorbRemaining > 0.0F)
{
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F){
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
}
else{
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
}
absorbRemaining -= 2.0F;
}
else
{
if (i * 2 + 1 < health){
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
}
else if (i * 2 + 1 == health){
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
}
GL11.glDisable(GL11.GL_BLEND);
mc.mcProfiler.endSection();
return;
}
/**
*
* @param event RenderGameOverlayEvent to invoke the method
*/
@SubscribeEvent(priority = EventPriority.NORMAL)
public void onRenderHUD(RenderGameOverlayEvent event){
// Checks to see if it is after (event.isCancelable() is false if the event is Post) the rendering of BOSSHEALTH
if(event.type != ElementType.BOSSHEALTH || event.isCancelable()) return;
res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
int width = res.getScaledWidth();
int height = res.getScaledHeight();
// Reset left_height back to default
left_height = 35;
mc.entityRenderer.setupOverlayRendering();
GL11.glEnable(GL11.GL_BLEND);
if(!mc.playerController.enableEverythingIsScrewedUpMode()){
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if(mc.playerController.shouldDrawHUD()){
// Ask if the game should render each, if so, do so
if(renderStamina) renderStamina(width, height);
if(renderHealth) renderHealth(width, height);
if(renderArmor) renderArmor(width, height);
}
}
}
/**
* renderArmor() copy-pasted from GuiIngameForge with a few changes:
*
* - post(ARMOR); and if(pre(ARMOR)) return; statements removed
* Forge didn't like me calling events from events from events.
* - if(pre(ARMOR)) return; replaced with if(event.isCancelable()) return; in onRenderHUD()
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
@Override
protected void renderArmor(int width, int height){
mc.mcProfiler.startSection("armor");
GL11.glEnable(GL11.GL_BLEND);
int left = width / 2 - 91;
int top = height - left_height;
int level = ForgeHooks.getTotalArmorValue(mc.thePlayer);
for (int i = 1; level > 0 && i < 20; i += 2)
{
if (i < level)
{
drawTexturedModalRect(left, top, 34, 9, 9, 9);
}
else if (i == level)
{
drawTexturedModalRect(left, top, 25, 9, 9, 9);
}
else if (i > level)
{
drawTexturedModalRect(left, top, 16, 9, 9, 9);
}
left += 8;
}
left_height += 10;
GL11.glDisable(GL11.GL_BLEND);
mc.mcProfiler.endSection();
return;
}
/**
* Renders a Three-in-one bar for stamina
*
* @param width is the width of the window for location calculation
* @param height is the height of the window for location calculation
*/
protected void renderStamina(int width, int height){
bind(staminaBar);
props = StaminaPlayer.get(mc.thePlayer); // Extended Properties
if(props == null || props.getStamina() == 0) return; //left_height;
mc.mcProfiler.startSection("stamina");
GL11.glEnable(GL11.GL_BLEND);
if(this.mc.playerController.isNotCreative()){
int left = width / 2 - 94;
int top = height - left_height;
int barWidth = 82;
int maximumFill = (int)(props.getMaximumStamina() / props.getStamina() * barWidth); // M
int currentFill = (int)(props.getCurrentStamina() / props.getStamina() * barWidth); // C
int adrenalineFill = (int)(props.getAdrenaline() / props.getStamina() * barWidth); // A
drawTexturedModalRect(left, top, 0, 0, barWidth, 5); // Background
// C M A
if(adrenalineFill >= maximumFill){
drawTexturedModalRect(left, top, 0, 15, adrenalineFill, 5);
if(maximumFill > 0){
drawTexturedModalRect(left, top, 0, 20, maximumFill, 5);
if(currentFill > 0){
drawTexturedModalRect(left, top, 0, 25, currentFill, 5);
}
}
// C A M
}else if(adrenalineFill >= currentFill){
if(maximumFill > 0){
drawTexturedModalRect(left, top, 0, 5, maximumFill, 5);
drawTexturedModalRect(left, top, 0, 20, adrenalineFill, 5);
if(currentFill > 0){
drawTexturedModalRect(left, top, 0, 25, currentFill, 5);
}
}
// A C M
}else if(maximumFill > 0){
drawTexturedModalRect(left, top, 0, 5, maximumFill, 5);
if(currentFill > 0){
drawTexturedModalRect(left, top, 0, 10, currentFill, 5);
if(adrenalineFill > 0){
drawTexturedModalRect(left, top, 0, 25, adrenalineFill, 5);
}
}
}
left_height += 10;
GL11.glDisable(GL11.GL_BLEND);
mc.mcProfiler.endSection();
}
return;
}
/**
* Calls the bindTexture() to binde the .png method to the rect drawn by the tesselator.
*
* @param location the ResourceLocation of the Texture
*/
private void bind(ResourceLocation location)
{
mc.getTextureManager().bindTexture(location);
}
private ScaledResolution res = null;
private StaminaPlayer props = null; // Extended Properties
}
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumCould you be a little more specific -> what, exactly, about the bar is not rendering correctly? Phrased another way, what do you expect to render, and what is rendering? Glad you fixed the height and chat issues, though.
Attached: Stamina Example.png
And this is the concept art that is in the assets folder:
Attached: staminaBar
This is a cropped screen shot:
Specifically, since the update part of the mod isn't working yet, I'm expected to see this:
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumIt looks like you might have multiple bars rendering over each other, or perhaps your texture is not the correct resolution. What I would do, if I were you, is try to just get a simple, solid bar to render first, without doing any of your stamina calculations - comment all that stuff out.
Another possibility is you may need to set the color before you render: GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
This way the color that you see in your texture file is the color that will render on the screen, as many of the Minecraft render functions change the openGL color settings.