Jump to content

Arrows not always hitting players


theishiopian

Recommended Posts

Im attempting to make a mod that reduces the damage of potion arrows to 0, with good results so far. However, I'm running into a peculiar bug. Whenever a tipped arrow is shot at a player, theres about a 50-50 chance of the arrow bouncing off the player. The chance increases to 100% with dispensers, and seems not to occur with strays. Messing with the entity hurt resistance timer thing didn't really seem to make a difference. Non player entities can be hit normally.

 

Code:

package com.theishiopian.usefulpotionarrows;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;

import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.potion.PotionType;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

public class DamageNullifier 
{
	//note to self: find these names in C:\Users\Andrew\.gradle\caches\minecraft\de\oceanlabs\mcp\mcp_snapshot\20171003\1.12.2\srgs
	Field potion = ReflectionHelper.findField(EntityTippedArrow.class, "potion", "field_184560_g");
	
	
	@SubscribeEvent
	public void Nullifier(ProjectileImpactEvent.Arrow event) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		EntityArrow arrow = event.getArrow();
		World world = arrow.getEntityWorld();
		
		if(!world.isRemote && arrow instanceof EntityTippedArrow)
		{
			potion.setAccessible(true);
			PotionType plocal = (PotionType) potion.get(arrow);
			
			if(!(plocal.getRegistryName().toString().equals("minecraft:empty")))
			{
				arrow.setDamage(0.0);
				if(event.getRayTraceResult().typeOfHit == RayTraceResult.Type.ENTITY)
					event.getRayTraceResult().entityHit.hurtResistantTime = 0;
			}
		}
	}
	
}

What could be causing this?

 

Link to comment
Share on other sites

3 hours ago, theishiopian said:

potion.setAccessible(true);

This is a very expensive operation that only needs to be done once! Put it in a static initialiser right below setting the field. That field reference should also be a constant

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

If your working on obfuscated files you’re doing something wrong

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

On 11/27/2018 at 7:20 AM, theishiopian said:

the files in the editor are obfuscated

 

Use ReflectionHelper with both the deobf and SRG names

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

Forge 1.12.2-14.23.5.2779 deprecated ReflectionHelper and changed the methods in ObfuscationReflectionHelper to only require an SRG name rather than both an SRG and MCP name. This is what @quadraxis was talking about.

  • Like 2

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Ok, I tried implementing the recommended changes. However, the game now crashes at startup when I try to access the field with an UnableToAccessFieldException. Im trying to get the field at startup in the postInit phase by calling reflectionSetup(). Did I misunderstand the phrase "static initialiser? Or can I not use static fields for this?"

 

Code:

 

package com.theishiopian.usefulpotionarrows;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.potion.PotionType;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

public class DamageNullifier 
{
	private static EntityTippedArrow arrow = null;
	
	static Field potion;
	
	public static void reflectionSetup()
	{
		potion = ObfuscationReflectionHelper.getPrivateValue(EntityTippedArrow.class, arrow, "potion", "field_184560_g");
		
		potion.setAccessible(true);
	}
	
	
	
	@SubscribeEvent
	public void Nullifier(ProjectileImpactEvent.Arrow event) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		arrow = (EntityTippedArrow) event.getArrow();
		World world = arrow.getEntityWorld();
		
		if(!world.isRemote && arrow instanceof EntityTippedArrow)
		{
			
			System.out.println(potion.get(arrow).toString());

//			if(!())
//			{
//				arrow.setDamage(0.0);
//				if(event.getRayTraceResult().typeOfHit == RayTraceResult.Type.ENTITY)
//					event.getRayTraceResult().entityHit.hurtResistantTime = 0;
//			}
		}
	}
	
}

 

 

 

 

 

 

Edited by theishiopian
initilizer
Link to comment
Share on other sites

Ok, after some further experimentation, I managed to figure out what a static initilizer is. Even after implementing static init properly, it still throws the same error, just now in a different place.

 

Code:

package com.theishiopian.usefulpotionarrows;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.potion.PotionType;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

public class DamageNullifier 
{
	private static EntityTippedArrow arrow;
	
	static Field potion;
	
	static
	{
		potion = ObfuscationReflectionHelper.getPrivateValue(EntityTippedArrow.class, arrow, "potion", "field_184560_g");
		
		potion.setAccessible(true);
	}
	
	
	
	@SubscribeEvent
	public void Nullifier(ProjectileImpactEvent.Arrow event) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		arrow = (EntityTippedArrow) event.getArrow();
		World world = arrow.getEntityWorld();
		
		if(!world.isRemote && arrow instanceof EntityTippedArrow)
		{
			
			System.out.println(potion.get(arrow).toString());

//			if(!())
//			{
//				arrow.setDamage(0.0);
//				if(event.getRayTraceResult().typeOfHit == RayTraceResult.Type.ENTITY)
//					event.getRayTraceResult().entityHit.hurtResistantTime = 0;
//			}
		}
	}
	
}

 

Stacktrace of exception:

https://pastebin.com/pKUwxBSr

Link to comment
Share on other sites

Your trying to get the instance field of a null instance. Get the field in a static initialiser (ReflectionHelper.findField), and then call Field.get(instanceOfArrow) in your normal code

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

Ah, that makes much more sense. Ill try that out in a few minutes, thank you so much!

EDIT: wait, isnt that what Im already doing? Field.get() is being called in the event handler.

EDIT2: I backtracked a bit, going back to my original, working code from the first post, except with a  static initilizer to get the field and no call of setAccessible. Now it works, but I need to run a few more tests to make sure the original problem is gone.

Edited by theishiopian
further information.
Link to comment
Share on other sites

Ok, so the reflection changes don't solve the original problem. Tipped arrows from players still only hit other players 50% of the time, and tipped arrows from dispensers still cant hit players at all.

 

Code now looks like this:

 

public class DamageNullifier 
{
	static Field potion;
	
	static
	{
		potion = ReflectionHelper.findField(EntityTippedArrow.class, "potion", "field_184560_g");
	}
	
	
	
	@SubscribeEvent
	public void Nullifier(ProjectileImpactEvent.Arrow event) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		EntityArrow arrow = event.getArrow();
		World world = arrow.getEntityWorld();
		
		if(!world.isRemote && arrow instanceof EntityTippedArrow)
		{
			PotionType plocal = (PotionType) potion.get(arrow);
			
			if(!(plocal.getRegistryName().toString().equals("minecraft:empty")))
			{
				arrow.setDamage(0.0);
				if(event.getRayTraceResult().typeOfHit == RayTraceResult.Type.ENTITY)
					event.getRayTraceResult().entityHit.hurtResistantTime = 0;
			}
		}
	}
	
}

 

Edited by theishiopian
Forgot a word
Link to comment
Share on other sites

33 minutes ago, theishiopian said:

Ok, so the reflection changes don't solve the original problem. Tipped arrows from players still only hit other players 50% of the time, and tipped arrows from dispensers still cant hit players at all.

So is the problem that the entity isn't getting the damage animation? That has to do with the damage value and how taking damage is handled on Entities.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

1 minute ago, theishiopian said:

So  maybe set the damage to 0.1 then?

Take a full look at the damage handling by setting a breakpoint in the EntityArrow class that handles the collision and then damage handling(its in the update method).

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

52 minutes ago, theishiopian said:

ok, ill do that. just to refresh my memory, how to i jump to the next breakpoint?

There is a button somewhere on your IDE.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

This happens because if the damage is 0 then EntityLivingBase#attackEntityFrom will return false which will cause the arrow to "bounce". You can have the exact same effect if you shoot the player in creative mode.

You might be able to circumvent the issue by using a LivingHurtEvent(or LivingDamageEvent) in combination with ProjectileImpactEvent. Basically in the impact event do your arrow check and if it is supposed to have no damage set some kind of flag to true(somewhere in your code that is) and also store the entity reference of the entity being damaged(that's important)(you may store something to identify the entity by, like it's UUID instead of a direct reference). Next in the Hurt/Damage event check for the flag - if it's true check whether the entity being damaged is the one you've stored the reference to(it should be but there are edge cases where it may not be). If it isn't set the flag to false, clear the reference and return. If it is you have a jackpot - set the damage to 0, flag to false, clear reference and be done. Alternatively don't clear the reference, but store it as a UUID to not leak like half of the game.

I've just tested this idea and it works flawlessly. Here is the code I've used.

private static boolean checkImpact = false;
    private static UUID hurtID = null;

    @SubscribeEvent
    public static void onArrowDamage(ProjectileImpactEvent event)
    {
        checkImpact = false;
        if (event.getEntity() instanceof EntityArrow && event.getRayTraceResult() != null && event.getRayTraceResult().typeOfHit == RayTraceResult.Type.ENTITY)
        {
            checkImpact = true;
            hurtID = event.getRayTraceResult().entityHit.getUniqueID();
        }
    }

    @SubscribeEvent
    public static void onHurt(LivingHurtEvent event)
    {
        if (checkImpact)
        {
            checkImpact = false;
            UUID id = event.getEntityLiving().getUniqueID();
            if (id.equals(hurtID))
            {
                event.setAmount(0);
            }

            hurtID = null;
        }
    }

Now admitedly you shouldn't have to store the entity reference, since the code flow should take you directly to the LivingHurtEvent from the ProjectileImpactEvent(in this case) but you never know with all the forge re-implementations around like them spigots and stuff. Since I can't guarantee the code flow within those implementations it's better to be sure.

  • Like 1
Link to comment
Share on other sites

I haven't been able to do any testing due to being really sick, so this is super appreciated! It looks like your code just nullifies all projectile damage, but it should be easy enough to merge my reflection code with your code to narrow it down to just potion arrows. Thanks for the suggestion, Ill be sure to list you as a contributor in the mcinfo file if this works!

Link to comment
Share on other sites

5 minutes ago, theishiopian said:

So, after some preliminary experimentation, I've discovered a small bug in your code, namely the event handlers being static means they don't register properly. Changing them to non static methods seems to fix it.

He was registering them in a different way than you were. If you register an instance of the class they can't be static, but if you register the class itself or use the @EventBusSubscriber on the top of the class then the methods must be static.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
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.
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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • 20 SLOT DEMO GRATIS PRAGMATIC PLAY x500 RUPIAH ANTI LAG & 20 DEMO SLOT MAHJONG WAYS PG SOFT GRATIS ANTI RUNGKAD KLIK DISINI DAFTAR DISINI SLOT VVIP << KLIK DISINI DAFTAR DISINI SLOT VVIP << KLIK DISINI DAFTAR DISINI SLOT VVIP << KLIK DISINI DAFTAR DISINI SLOT VVIP << SITUS SLOT GACOR 88 MAXWIN X500 HARI INI TERBAIK DAN TERPERCAYA GAMPANG MENANG Dunia Game gacor terus bertambah besar seiring berjalannya waktu, dan sudah tentu dunia itu terus berkembang serta merta bersamaan dengan berkembangnya SLOT GACOR sebagai website number #1 yang pernah ada dan tidak pernah mengecewakan sekalipun. Dengan banyaknya member yang sudah mempercayakan untuk terus menghasilkan uang bersama dengan SLOT GACOR pastinya mereka sudah percaya untuk bermain Game online bersama dengan kami dengan banyaknya testimoni yang sudah membuktikan betapa seringnya member mendapatkan jackpot besar yang bisa mencapai ratusan juta rupiah. Best online Game website that give you more money everyday, itu lah slogan yang tepat untuk bermain bersama SLOT GACOR yang sudah pasti menang setiap harinya dan bisa menjadikan bandar ini sebagai patokan untuk mendapatkan penghasilan tambahan yang efisien dan juga sesuatu hal yang fix setiap hari nya. Kami juga mendapatkan julukan sebagai Number #1 website bocor yang berarti terus memberikan member uang asli dan jackpot setiap hari nya, tidak lupa bocor itu juga bisa diartikan dalam bentuk berbagi promosi untuk para official member yang terus setia bermain bersama dengan kami. Berbagai provider Game terus bertambah banyak setiap harinya dan terus melakukan support untuk membuat para official member terus bisa menang dan terus maxwin dalam bentuk apapun maka itu langsung untuk feel free to try yourself, play with SLOT GACOR now or never !
    • BOCORAN POLA SLOT GACOR MAHJONG WAYS MAXWIN x500 PETIR MERAH HARI INI HINGGA MALAM INI KLIK DISINI DAFTAR SLOT VVIP << KLIK DISINI DAFTAR SLOT VVIP << KLIK DISINI DAFTAR SLOT VVIP << KLIK DISINI DAFTAR SLOT VVIP << SITUS SLOT GACOR 88 MAXWIN X500 HARI INI TERBAIK DAN TERPERCAYA GAMPANG MENANG Dunia Game gacor terus bertambah besar seiring berjalannya waktu, dan sudah tentu dunia itu terus berkembang serta merta bersamaan dengan berkembangnya SLOT GACOR sebagai website number #1 yang pernah ada dan tidak pernah mengecewakan sekalipun. Dengan banyaknya member yang sudah mempercayakan untuk terus menghasilkan uang bersama dengan SLOT GACOR pastinya mereka sudah percaya untuk bermain Game online bersama dengan kami dengan banyaknya testimoni yang sudah membuktikan betapa seringnya member mendapatkan jackpot besar yang bisa mencapai ratusan juta rupiah. Best online Game website that give you more money everyday, itu lah slogan yang tepat untuk bermain bersama SLOT GACOR yang sudah pasti menang setiap harinya dan bisa menjadikan bandar ini sebagai patokan untuk mendapatkan penghasilan tambahan yang efisien dan juga sesuatu hal yang fix setiap hari nya. Kami juga mendapatkan julukan sebagai Number #1 website bocor yang berarti terus memberikan member uang asli dan jackpot setiap hari nya, tidak lupa bocor itu juga bisa diartikan dalam bentuk berbagi promosi untuk para official member yang terus setia bermain bersama dengan kami. Berbagai provider Game terus bertambah banyak setiap harinya dan terus melakukan support untuk membuat para official member terus bisa menang dan terus maxwin dalam bentuk apapun maka itu langsung untuk feel free to try yourself, play with SLOT GACOR now or never !
    • Museumbola merupakan wadah judi online terkhusus untuk sbobet atau judi bola. Dengan daftar dan deposit menggunakan BANK BCA, Anda berkesempatan mendapatkan prediksi jitu pertandingan secara update setiap hari yang bisa anda jadikan acuan untuk bermain judi bola. Hanya dengan 10 ribu rupiah dan anda bermain Mix Parlay menggunakan prediksi yang telah di sediakan oleh kami, anda akan memenangkan jutaan rupiah. Yuk segera klik DAFTAR sekarang juga.
    • I was just trying to play my modded world when i randomly got this crash for no reason. I sorted through like every mod and eventually I realized it was LLibrary but I can't seem to find a solution to fix the crashing. I can't lose the world that I have that uses this mod please help me. Here's the report: https://pastebin.com/0D00B79i If anyone has a solution please let me know.  
    • 🤑DAFTAR & LOGIN🤑 🤑DAFTAR & LOGIN🤑 🤑DAFTAR & LOGIN🤑   Daftar Slot Ligawin88 adalah bocoran slot rekomendasi gacor dari Ligawin88 yang bisa anda temukan di SLOT Ligawin88. Situs SLOT Ligawin88 hari ini yang kami bagikan di sini adalah yang terbaik dan bersiaplah untuk mengalami sensasi tak terlupakan dalam permainan slot online. Temukan game SLOT Ligawin88 terbaik dengan 100 pilihan provider ternama yang dipercaya akan memberikan kepuasan dan kemenangan hari ini untuk meraih x500. RTP SLOT Ligawin88 merupakan SLOT Ligawin88 hari ini yang telah menjadi pilihan utama bagi pemain judi online di seluruh Indonesia. Setiap harinya jutaan pemain memasuki dunia maya untuk memperoleh hiburan seru dan kemenangan besar dalam bermain slot dengan adanya bocoran RTP SLOT Ligawin88. Tidak ada yang lebih menyenangkan daripada mengungguli mesin slot dan meraih jackpot x500 yang menggiurkan di situs SLOT Ligawin88 hari ini yang telah disediakan SLOT Ligawin88. Menangkan jackpot besar x500 rajanya maxwin dari segala slot dan raih kemenangan spektakuler di situs Ligawin88 terbaik 2024 adalah tempat yang menyediakan mesin slot dengan peluang kemenangan lebih tinggi daripada situs slot lainnya. Bagi anda yang mencari pengalaman judi slot paling seru dan mendebarkan, situs bo SLOT Ligawin88 terbaik 2024 adalah pilihan yang tepat. Jelajahi dunia slot online melalui situs SLOT Ligawin88 di link SLOT Ligawin88.
  • Topics

×
×
  • Create New...

Important Information

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