Jump to content

[1.7.2]Add vanilla mob xp drop..


f1rSt1kChannel

Recommended Posts

My code:

@SubscribeEvent
public void dropXP(LivingDropsEvent event){
	EntityLivingBase entity = event.entityLiving;
	if(entity != null){
		EntityLivingBase living = (EntityLivingBase)entity;
		int recentlyHit = ObfuscationReflectionHelper.getPrivateValue(EntityLivingBase.class, living, "recentlyHit");
		if(!living.worldObj.isRemote && recentlyHit == 0){
			Method getExperiencePoints = null;
			int xp = 0;
			try{
				Class fake = Class.forName("net.minecraft.entity.EntityLivingBase");
				getExperiencePoints = fake.getMethod("getExperiencePoints", EntityPlayer.class);
				xp = (Integer)getExperiencePoints.invoke(null, (Object[])null);
			}catch(Exception e){ 
				logger.error("Error!", e);
			}
			System.out.println(xp);
			while(xp > 0){
				int cap = EntityXPOrb.getXPSplit(xp);
				xp -= cap;
				living.worldObj.spawnEntityInWorld(new EntityXPOrb(living.worldObj, living.posX, living.posY, living.posZ, cap));
			}
		}
	}
}

Error:

java.lang.NoSuchMethodException: net.minecraft.entity.EntityLivingBase.getExperiencePoints(net.minecraft.entity.player.EntityPlayer)
at java.lang.Class.getMethod(Unknown Source) ~[?:1.7.0_55]
at agravaine.easyxp.EasyXP.dropXP(EasyXP.java:54) [EasyXP.class:?]
at cpw.mods.fml.common.eventhandler.ASMEventHandler_7_EasyXP_dropXP_LivingDropsEvent.invoke(.dynamic) [?:?]
at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:51) [ASMEventHandler.class:?]
at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:122) [EventBus.class:?]
at net.minecraftforge.common.ForgeHooks.onLivingDrops(ForgeHooks.java:297) [ForgeHooks.class:?]
at net.minecraft.entity.EntityLivingBase.onDeath(EntityLivingBase.java:1039) [EntityLivingBase.class:?]
at net.minecraft.entity.monster.EntityCreeper.onDeath(EntityCreeper.java:200) [EntityCreeper.class:?]
at net.minecraft.entity.EntityLivingBase.attackEntityFrom(EntityLivingBase.java:950) [EntityLivingBase.class:?]
at net.minecraft.entity.monster.EntityMob.attackEntityFrom(EntityMob.java:84) [EntityMob.class:?]
at net.minecraft.entity.EntityLivingBase.fall(EntityLivingBase.java:1139) [EntityLivingBase.class:?]
at net.minecraft.entity.monster.EntityCreeper.fall(EntityCreeper.java:83) [EntityCreeper.class:?]
at net.minecraft.entity.Entity.updateFallState(Entity.java:1042) [Entity.class:?]
at net.minecraft.entity.EntityLivingBase.updateFallState(EntityLivingBase.java:234) [EntityLivingBase.class:?]
at net.minecraft.entity.Entity.moveEntity(Entity.java:856) [Entity.class:?]
at net.minecraft.entity.EntityLivingBase.moveEntityWithHeading(EntityLivingBase.java:1689) [EntityLivingBase.class:?]
at net.minecraft.entity.EntityLivingBase.onLivingUpdate(EntityLivingBase.java:2027) [EntityLivingBase.class:?]
at net.minecraft.entity.EntityLiving.onLivingUpdate(EntityLiving.java:431) [EntityLiving.class:?]
at net.minecraft.entity.monster.EntityMob.onLivingUpdate(EntityMob.java:39) [EntityMob.class:?]
at net.minecraft.entity.EntityLivingBase.onUpdate(EntityLivingBase.java:1820) [EntityLivingBase.class:?]
at net.minecraft.entity.EntityLiving.onUpdate(EntityLiving.java:250) [EntityLiving.class:?]
at net.minecraft.entity.monster.EntityMob.onUpdate(EntityMob.java:47) [EntityMob.class:?]
at net.minecraft.entity.monster.EntityCreeper.onUpdate(EntityCreeper.java:176) [EntityCreeper.class:?]
at net.minecraft.world.World.updateEntityWithOptionalForce(World.java:2254) [World.class:?]
at net.minecraft.world.WorldServer.updateEntityWithOptionalForce(WorldServer.java:697) [WorldServer.class:?]
at net.minecraft.world.World.updateEntity(World.java:2214) [World.class:?]
at net.minecraft.world.World.updateEntities(World.java:2064) [World.class:?]
at net.minecraft.world.WorldServer.updateEntities(WorldServer.java:528) [WorldServer.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:697) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:608) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:482) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:746) [MinecraftServer$2.class:?]
0

This method is exists!

Line 417

protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
    {
        return 0;
    }

Link to comment
Share on other sites

Not work...

@SubscribeEvent
public void dropXP(LivingDropsEvent event){
	EntityLivingBase entity = event.entityLiving;
	if(entity != null){
		EntityLivingBase living = (EntityLivingBase)entity;
		if(!living.worldObj.isRemote && !event.recentlyHit){
			Method getExperiencePoints = null;
			int xp = 0;
			try{
				getExperiencePoints = EntityLivingBase.class.getDeclaredMethod("getExperiencePoints", EntityPlayer.class);
				getExperiencePoints.setAccessible(true);
				xp = (Integer)getExperiencePoints.invoke(null, (Object[])null);
			}catch(Exception e){ 
				logger.error("Error!", e);
			}
			System.out.println(xp);
			while(xp > 0){
				int cap = EntityXPOrb.getXPSplit(xp);
				xp -= cap;
				living.worldObj.spawnEntityInWorld(new EntityXPOrb(living.worldObj, living.posX, living.posY, living.posZ, cap));
			}
		}
	}
}

d) I do not understand what you wrote... :\

Link to comment
Share on other sites

Right?

public static Method getExperiencePoints(){
Method method = null;
try{
	method = EntityLivingBase.class.getDeclaredMethod("getExperiencePoints", EntityPlayer.class);
}catch(Exception e){}
method.setAccessible(true);
return method;
}

public static final Method xpPoints = getExperiencePoints();

xp = (Integer)xpPoints.invoke(living, (Object[])null);

 

?

Link to comment
Share on other sites

@diesieben07, what do you think about creating an "accesser" class in a Minecraft package to get to protected methods and fields?  For example, the problem here is that the getExperiencePoints() method is protected (strangely).  But I found I can access it and achieve the OP's goal of intercepting the xp drop to top it up with more xp like this.

 

CoolAlias suggested this method to someone yesterday, and I just had to try it out.  It seems to work!

 

I create a class (in my project) that says it's in the same Minecraft package as the EntityAnimal for example.

package net.minecraft.entity.passive;

import net.minecraft.entity.player.EntityPlayer;

public class EntityPassiveAccessor 

{
public static int getPassiveXP(EntityAnimal theEntity, EntityPlayer thePlayer) 
{
	// DEBUG
	System.out.println("Last attack by player: Accessed Passive Entity XP");
	return theEntity.getExperiencePoints(thePlayer);
}
}

Notice the package in the class is a Minecraft package.

 

And then I can now access the method from within my project by calling this class.  For example, I can handle the living drops event like this:

    @SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)
    public void onEvent(LivingDropsEvent event)
    {
    	if (event.source.getEntity() instanceof EntityPlayer)
    	{
        	EntityPlayer thePlayer = (EntityPlayer) event.source.getEntity();
    		// DEBUG
    		System.out.println("Killed by a player");
    	if (event.entityLiving instanceof EntityAnimal)
    	{
    		EntityAnimal entityAnimal = (EntityAnimal)event.entityLiving;
    		// DEBUG
    		System.out.println("The animal's XP drop is ="+net.minecraft.entity.passive.EntityPassiveAccessor.getPassiveXP(entityAnimal, thePlayer));
    	}
    	}
    }

You can see that I am now calling that class which has a method that accesses the protected method in the EntityAnimal class.

 

And the console output from when I kill a cow looks like this was successful:

Killed by a player
Last attack by player: Accessed Passive Entity XP
The animal's XP drop is =3

Of course I could then check the XP and if I wanted to drop some extra I could do that in the handler event.

 

Anyway, it seems to work to create a class within my project that is actually in package elsewhere.  Is that bad practice?  Is there an actual problem with this?

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

Link to comment
Share on other sites

@diesieben07, what do you think about creating an "accesser" class in a Minecraft package to get to protected methods and fields?  For example, the problem here is that the getExperiencePoints() method is protected (strangely).  But I found I can access it and achieve the OP's goal of intercepting the xp drop to top it up with more xp like this.

In theory this works, but it's bad practice. At some point in the future FML / Forge might even put a system in place to prevent this, for good reasons. Don't put stuff in packages that are not yours.

 

public class EntityPassiveAccessor
See? Already made a mistake IF you were to use this method. You have to keep in mind that you are in a package which is not yours. If another mod would do the same thing, and also name their class EntityPassiveAccessor (as that's the first name that comes to mind, right?) - BOOM.

 

So please people, use Reflection or AccessTransformers.

If used correctly, Reflection is barely slower than normal method invocation and unless you're working in time-critical areas of the code (Rendering, things that happen every tick, etc.) you will be just fine by using Reflection.

Using ATs also recently got a whole lot easier since now you don't even need to make a Coremod to use them.

 

Thanks for the ideas on why this might be bad idea.  I should use reflection more often, but it has always seemed to me to be more hacking than modding, but since it is a solid way to do most of these things I guess it is the way to go.  I need to revisit ATs as well.

 

Too bad simply changing package isn't good idea -- it is sooo easy!

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

Link to comment
Share on other sites

Helped me FakePlayer :)

FakePlayerFactory.getMinecraft ((WorldServer) world)

Working version:

public static final Method xpPoints = getExperiencePoints();

@EventHandler
public void preInit(FMLPreInitializationEvent event){
	MinecraftForge.EVENT_BUS.register(this);
}

@SubscribeEvent
public void dropXP(LivingDropsEvent event){
	EntityLivingBase entity = event.entityLiving;
	World world = entity.worldObj;
	if(entity != null){
		EntityLivingBase living = (EntityLivingBase)entity;
		if(!world.isRemote && !event.recentlyHit){
			int xp = 0;
			try{
				xp = (Integer)xpPoints.invoke(living, FakePlayerFactory.getMinecraft((WorldServer)world));
			}catch(Exception e){}
			while(xp > 0){
				int cap = EntityXPOrb.getXPSplit(xp);
				xp -= cap;
				living.worldObj.spawnEntityInWorld(new EntityXPOrb(living.worldObj, living.posX, living.posY, living.posZ, cap));
			}
		}
	}
}

public static Method getExperiencePoints(){
	Method method = null;
	try{
		method = EntityLivingBase.class.getDeclaredMethod("getExperiencePoints", EntityPlayer.class);
		method.setAccessible(true);
	}catch(Exception e){}
	return method;
}

Thank you, guys! =)

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



×
×
  • Create New...

Important Information

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