Forge returning NoSuchMethodExcepton on Entity#getName() - java

I'm attempting to write a (very simple) Forge mod that watches for and alerts on chicken spawns, but the code refuses to work. Instead, it throws a NoSuchMethodException when I attempt to read the entity name.
My code is as follows:
#SubscribeEvent
public void OnEntityJoinWorld(EntityJoinWorldEvent event) {
if (!(event.getEntity() instanceof EntityChicken)) {
return;
}
Entity chicken = event.getEntity();
String message = "Chicken named " + chicken.getName() + " spawned at " + chicken.posX
+ "," + chicken.posY
+ "," + chicken.posZ
+ ".";
Minecraft.getMinecraft().thePlayer.addChatMessage(new TextComponentString(message));
LOGGER.info(message);
}
The specific error is:
java.lang.NoSuchMethodError: net.minecraft.entity.Entity.getName()Ljava/lang/String;
Both the Forge and Minecraft versions being used are the same, so either I'm overlooking something very simple, or this just isn't how I'm supposed to do what I'm trying to do. How can I fix this issue?

Be sure to compile your project using the Gradle build option as opposed to the jar option.
When using just jar, Gradle will not re-obfuscate all of Minecraft's code. In turn, this will cause it (obviously) not to be able to find the non-obfuscated methods and names.

Shouln't you use:
EntityChicken chicken = event.getEntity();
And then import EntityChicken?
EDIT:
your error is becouse when you do chicken.getName(), it wants to get the name of event.getEntity() and the type of event.getEntity() is set to Entity which gives the error. What you should do is change the type of event.getEntity() to EntityChicken, as said above

Related

The method sign.setline is not working

im haveing a problem running a setline command
witch i want to set the line of a sign with..
it isn't doing anything
This is the part of the code that has the setline method in it it will run with a few other things when the player will give the input (the "if (SignEvent.isNumericArray(times))" is true for sure and the code is running i did check that )
if (SignEvent.isNumericArray(times)){
double uses = Double.parseDouble(times);
uses = uses -1;
sign.setLine(2 , uses + "/" + str[1] + parts[1]);
if (uses <= 0){
sign.setLine(0, ChatColor.STRIKETHROUGH + "StartPayment");
}
}
i did check a few things :
no errors in console or eclipse error list
object sign is type Sign imported from import org.bukkit.block.Sign
object sign is the right sign (checked by doing e.getPlayer().sendMessage(sign.getLine(0)); it worked..
no matter what the string is it isn't working
no matter where i put this line of code its not working
the this line is running
i just have no idea what could i do to fix it i tried a lot of things and im pretty sure the problem is in the
sign.setLine(2 , uses + "/" + str[1] + parts[1]); line
any one have any idea for what did i do wrong ?
Note: no matter where in this method i put the setline method or with what string/lineIndex ,it isn't doing anything
I think you have to execute sign.update(); after a modification to apply changes.

Can I run a .java class in a specific java program with its variables?

So again this is one of my Java minecraft plugins, and I'm trying to make a command that runs a specific code that will run on the server, so what I stumbled on is
String code = "package code; \n"
+ "public class MyClass { \n"
+ " public void myMethod(){ \n"
+ " " + args[1] + "\n"
+ " } \n"
+ "}";
Dir.save(code, new File(getDataFolder(), "MyClass.java"));
so this is my code it will try to save the string in a file, btw please tell me if this string will work as it is meant to be.
then what I want to do In here is that I want to compile this file and run it in my server, its like an external file out side the program, so how do I do it.
How do I run this MyClass.java with the libraries of the server's codes, because I want the code to run with what the server offers from classes!
this is my code it will try to save the string in a file, btw please tell me if this string will work as it is meant to be
This part of the question could have been ommitted. You may try to run that code snippet and check if the file will be saved as you want it to; if it is, then the answer is yes. Otherwise, it is no.
It is possible to dinamically compile and execute code in the server. To achieve this effect, you may want to take a look at:
Dynamic code execution
Set up Java compiler on server?
Java's JavaCompiler interface

Eclipse RCP: How to programmatically get Problems View records

On Eclipse Luna, I need to programmatically build java projects and then retrieve the Problems View's records. I use the following code
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IResource resource = workspace.getRoot();
IMarker[] markers = resource.findMarkers(IMarker.MARKER, true, IResource.DEPTH_INFINITE);
for (IMarker m : markers) {
System.out.println("Id: " + m.getId());
System.out.println("Message: " + m.getAttribute(IMarker.MESSAGE));
System.out.println("Source ID: " + m.getAttribute(IMarker.SOURCE_ID));
System.out.println("Location: " + m.getAttribute(IMarker.LOCATION));
System.out.println("Line Number: " + m.getAttribute(IMarker.LINE_NUMBER));
System.out.println("Marker: " + m.getAttribute(IMarker.MARKER));
}
The message and line number are printed correctly. But IMarker.SOURCE_ID returns "JDT" and IMarker.LOCATION is always null.
Anybody knows how can I get the data shown as "Resource" and "Path" on the Problems View? I cannot create any custom Marker view using MarkerSupportView. I need to access the existing Problems View in a programmatic way. Thank you for any suggestion.
Got it. Use getResource() instead of getAttribute().
The markers API is pretty flexible, you should read the documentation.
Long story short, there will be other attributes that you're not looking at. Try calling getAttributes and dumping them out.

Unable to get version name in code after moving to Gradle

I've just moved one of my Android projects over to Gradle, and as per recommendations inside the IDE and online I've moved all the configurations (min/max sdk, version name/code etc) into the build.gradle file.
Now a bug has been reported from a customer that where he could usually see the version name and code inside the product there is nothing.
After checking it out I've found out that the usual way of extracting those values has stopped working after I removed the android:versionCode="" and android:versionName="" tags from AndroidManifest.xml. I have verified that it works when these values are there.
Now I've been trying to search for a way of extracting these same values to use in code, but I have not found any reference to this behaviour else where (this not working like this).
The code I used to use to get the values was to simply extract them from the PackageManager as so
try {
PackageInfo pInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0);
return pInfo.versionName + " Build " + pInfo.versionCode;
} catch(PackageManager.NameNotFoundException e){
e.printStackTrace();
}
All hints, tips or solutions appreciated.
Use the BuildConfig class to fetch your version code which are defined in build.gradle file:
Log.e(TAG, BuildConfig.VERSION_NAME + " Build " + BuildConfig.VERSION_CODE);

How can I modify a java.lang class on the fly?

I'm looking for a way to add fields to an Thread on the fly by rewriting the byte code and reloading the class, not sure if it is at all possible. Any pointers welcome. I found some info on modifying and loading a class, and I know JRebel can seamlessly hot swap your code but not sure if the same approach/tools apply here.
The motivation here is exploring a theoretically better alternative to thread local objects. Should the method work I should be able to replace thread local with an annotation and the result should outperform current JDK implementation.
PS: Please save me the "root of all evil speech"
Clarifying use case:
Imagine I have a class with a ThreadLocal:
class A {
ThreadLocal&ltCounter&gt counter;
...
counter.get().inc()
}
I'd like to replace that with an annotation:
class A {
#ThreadLocal
Counter counter;
...
counter.inc()
}
But instead of the above code getting generated I'd like to mutate Thread such that Thread will now have an Acounter field and the actual code will be:
class A {
// Nothing here, field is now in Thread
...
Thread.currentThread().Acounter.inc()
}
At present it is impossible to redefine a class at runtime such that the redefinition will result in new methods or fields. This is due to the complexity involved in scanning the heap for all existing instances and transforming them + their references + potential Unsafe field offset base updaters (like AtomicFieldUpdater).
This limitation may be lifted as part of the JEP-159 but as discussed on the concurrency-interest mailing group this is a big impact change so may never happen at all.
Using Javaassist/similar will allow the transformation of a class to a new class with new methods/fields. This class can be loaded by a ClassLoader and used at runtime, but it's definition will not replace existing instances. So it will not be possible to use this method combined with an agent to redefine the class as an instrumentation redefinition is limited such that: "The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields ..." see here.
So for now, NO.
If you would like to change the behaviour of "class" at runtime, you could try javassist. API is here
I have seen custom class loading solution that dynamically reloaded JARs - you define one ClassLoader per JAR file and use it to load the classes from that JAR; to reload entire JAR you just "kill" its ClassLoader instance and create another one (after you replace the JAR file).
I don't think it's possible to tweak Java's internal Thread class this way because you don't have control over System ClassLoader. A possible solution is to have a CustomThreadWeaver class that would generate a new class extending Thread with the variables you need and use a custom DynamicWeavedThreadClassLoader to load them.
Good luck and show us your monster when you succeed ;-)
Possible
using instrumentation, and possibly libraries like javassist to modify code on fly. (however, adding and removing fields, methods or constructors are currently not possible)
//Modify code using javassist and call CtClass#toBytecode() or load bytecode from file
byte[] nevcode;
Class<?> clz = Class.forName("any.class.Example");
instrumentationInstace.redefineClasses(new ClassDefinition(clz, nevcode));
Do not forget to add Can-Redefine-Classes: true to your java agent's manifest.
Real example - optimizing java < 9 string.replace(CharSequence, CharSequence) using javassist:
String replace_src =
"{String str_obj = this;\n"
+ "char[] str = this.value;\n"
+ "String find_obj = $1.toString();\n"
+ "char[] find = find_obj.value;\n"
+ "String repl_obj = $2.toString();\n"
+ "char[] repl = repl_obj.value;\n"
+ "\n"
+ "if(str.length == 0 || find.length == 0 || find.length > str.length) {\n"
+ " return str_obj;\n"
+ "}\n"
+ "int start = 0;\n"
+ "int end = str_obj.indexOf(find_obj, start);\n"
+ "if(end == -1) {\n"
+ " return str_obj;\n"
+ "}\n"
+ "int inc = repl.length - find.length;\n"
+ "int inc2 = str.length / find.length / 512;\ninc2 = ((inc2 < 16) ? 16 : inc);\n"
+ "int sb_len = str.length + ((inc < 0) ? 0 : (inc * inc2));\n"
+ "StringBuilder sb = (sb_len < 0) ? new StringBuilder(str.length) : new StringBuilder(sb_len);\n"
+ "while(end != -1) {\n"
+ " sb.append(str, start, end - start);\n"
+ " sb.append(repl);\n"
+ " start = end + find.length;\n"
+ " end = str_obj.indexOf(find_obj, start);\n"
+ "}\n"
+ "if(start != str.length) {\n"
+ " sb.append(str, start, str.length - start);\n"
+ "}\n"
+ "return sb.toString();\n"
+"}";
ClassPool cp = new ClassPool(true);
CtClass clz = cp.get("java.lang.String");
CtClass charseq = cp.get("java.lang.CharSequence");
clz.getDeclaredMethod("replace", new CtClass[] {
charseq, charseq
}).setBody(replace_src);
instrumentationInstance.redefineClasses(new ClassDefinition(Class.forName(clz.getName(), false, null), clz.toBytecode()));
This seems to be a question of using the right tool for the job. A similar question has been asked here: Another Stack Overflow Question and the Javaassist byte code manipulation library was a possible solution.
But without further detail into the reasons why this is being attempted, it seems like the real answer is to use the right tool for the job. For example, with Groovy the ability to dynamically add methods to the language.
You could try creating a JVM Agent that makes use of the java.lang.instrument API and more specifically make use of the retransform method that " facilitates the instrumentation of already loaded classes" and then make use of Javassist (or ASM) as mentioned to deal with the bytecode.
More info on the java.lang.instrument API
To do what you want, the simpler alternative would be to use a subclass of Thread, run it, and then inside that thread execute the code from your example (together with a cast of currentThread() to your subclass).
What you are attempting to do is not possible.
Since you already know about ThreadLocal, you already know what the suggested solution is.
Alternatively, you can sub-class Thread and add your own fields; however, only those threads that you explicitly create of that class will have those fields, so you will still have to be able to "fall back" to using a thread local.
The real question is "why?", as in "why is a thread local insufficient for your requirements?"

Categories