Jump to content

[1.7.10] [Solved] How to modify accessibility of fields (the advanced way)


kauan99

Recommended Posts

Hi. I'm trying to make an addon for buildcraft.

 

I need to extend the TileEntity for the Quarry. My problem is, I need access to some private fields on that class. I would use reflection if it was a one time thing, but I need to access those fields pretty often. I was trying to read the tutorial for access transformers, but I couldn't understand it. So i decided to ask here for clarification.

 

Here's what I want to do:

 

public class ABuildCraftClass
{
   private int aField;

   public void aMethod()
   {
       //does stuff that requires reading aField.
   }
}

public class MyClass extends ABuildCraftClass
{
   @Override
   public void aMethod()
   {
      //I need to override this one but I will still need the value of aField.
   }
}

 

how can I do this without using reflection for every access?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Link to comment
Share on other sites

I know how to do it using reflection, I'm just afraid it may hurt performance. it is not only one field, I simplified it for the sake of the example. it's actually 5 fields. And this method will be called often when the machine is on.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Link to comment
Share on other sites

While it is good to worry about performance when choosing an approach to a problem, I really don't think that reflecting 5 fields every tick on an occasional tile entity will have any real impact.

 

Generally, regarding performance optimization you should first code "correctly" (meaning in simplest, common, readable way) and only optimize if you identify a problem. Otherwise you can spend a lot of time and pain on something that didn't matter in the first place.

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

Link to comment
Share on other sites

Also: If reflection is really (measurably) hurting the performance of your mod there is a better way (requiring Java 7 though, but seriously, who uses Java 6...):

 

private static final MethodHandle fieldGet;

static {
    Field field = SomeClass.class.getDeclaredField("field");
    field.setAccessible(true);
    fieldGet = MethodHandles.publicLookup().unreflectGetter(field);
}

// then to call it:
int value = (int) fieldGet.invokeExact((SomeClass) someClassInstance);

 

Important hints:

- It is crucial that the field storing the MethodHandle is static and final. Otherwise the JVM will at the moment not optimize this as well as it could.

 

- The casts when calling invokeExact are necessary. The "exact" part means that you if you pass e.g. a subclass of SomeClass into it you still have to explicitly specify the cast to SomeClass, otherwise it will not work.

 

- For setting repeat the process and replace unreflectGetter with unreflectSetter.

 

- For invoking methods just use unreflect on a Method instance.

 

- If you follow the first point this will optimize very nicely and there is no (yes, no, not almost no) noticeable difference in performance when compared to a direct field access.

 

nice! so this line

 

fieldGet = MethodHandles.publicLookup().unreflectGetter(field);

 

creates a public getter for the field, and I don't need reflection to read it anymore? It will work just as if SomeClass had a public getter for field?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Link to comment
Share on other sites

I press the green button and minecraft loads and so does my mod and everything works fine, but then, when trying to build, I get compilation errors.

 

this is gradle.log:

 

****************************
Powered By MCP:             
http://modcoderpack.com/    
Searge, ProfMobius, Fesh0r, 
R4wk, ZeuX, IngisKahn, bspkrs
MCP Data version : unknown
****************************
:compileApiJava UP-TO-DATE
:processApiResources UP-TO-DATE
:apiClasses UP-TO-DATE
:sourceMainJava UP-TO-DATE
:compileJavawarning: [options] bootstrap class path not set in conjunction with -source 1.6
C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterQuarryTileEntity.java:94: error: incompatible types: Object cannot be converted to int
		int targetX = (int) targetXGetter.invokeExact((TileQuarry)this);
		                                             ^
C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterQuarryTileEntity.java:95: error: incompatible types: Object cannot be converted to int
		int targetY = (int) targetYGetter.invokeExact((TileQuarry)this);
		                                             ^
C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterQuarryTileEntity.java:96: error: incompatible types: Object cannot be converted to int
		int targetZ = (int) targetZGetter.invokeExact((TileQuarry)this);
		                                             ^
Note: C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterBlockMiner.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterBlockMiner.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
3 errors
1 warning
FAILED

 

this is build.gradle:

 

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }
        maven {
            name = "sonatype"
            url = "https://oss.sonatype.org/content/repositories/snapshots/"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
    }
}

apply plugin: 'forge'

version = "1.7.10-0.1a"
group= "mod.betterquarry.main.BetterQuarry" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "BetterQuarry"

minecraft {
    version = "1.7.10-10.13.4.1448-1.7.10"
    runDir = "eclipse"
}

dependencies {    
    compile files("C:/Forge/src/libs/buildcraft-7.0.20-dev.jar")
}

processResources
{
    // this will ensure that this task is redone when the versions change.
    inputs.property "version", project.version
    inputs.property "mcversion", project.minecraft.version

    // replace stuff in mcmod.info, nothing else
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
                
        // replace version and mcversion
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }
        
    // copy everything else, thats not the mcmod.info
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

 

I changed the method to invoke and then I got another error.

 

C:\Forge\build\sources\java\mod\betterquarry\tileentities\BetterQuarryTileEntity.java:100: error: method invoked with incorrect number of arguments; expected 2, found 1
			minerSetter.invokeExact((TileQuarry)this, (BlockMiner)(new BetterBlockMiner(worldObj, this, targetX, targetY - 1, targetZ)));

 

Which I fixed changing invokeExact to invokeWithArguments. Problem is, when I test the compiled .jar putting it into my mods folder, it throws an exception when I place my block on the world:

 

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    mod/betterquarry/tileentities/BetterQuarryTileEntity.positionReached()V @15: invokevirtual
  Reason:
    Type 'mod/betterquarry/tileentities/BetterQuarryTileEntity' (current frame, stack[1]) is not assignable to '[Ljava/lang/Object;'
  Current Frame:
    bci: @15
    flags: { }
    locals: { 'mod/betterquarry/tileentities/BetterQuarryTileEntity' }
    stack: { 'java/lang/invoke/MethodHandle', 'mod/betterquarry/tileentities/BetterQuarryTileEntity' }

 

I don't know how to fix this! If I change back to invokeExact it won't compile. If I use invoke it won't run.

 

also how do I make those exceptions get thrown when I use eclipse's Minecraft client? I wanted to know when my code is broken before trying to build it.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Link to comment
Share on other sites

As I said, MethodHandles are Java 7 and thus require you to compile with Java 7. You can change this like this.

 

awesome! thanks again. I put 1.8 because I have Java 8 and I think this way both gradle and eclipse will use the same compiler. It works perfectly now.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Link to comment
Share on other sites

It will do magic™ (read sun.misc.Unsafe) stuff under the hood

 

And I have a new Skype status message.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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.