Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Guys, please help me get through this horrible NoClassDefFound exception.

Featured Replies

Posted

Hey fellas!

So I've been working on a mod for my Minecraft server that adds "admin tools" ( that's code for "trolling commands" ( : )

It's been pretty smooth so far: I've heard them scream as they were chased by every enemy in the entire world, I've watched as they mysteriously turned into potatoes, and I've even gotten to hear them say strange things like "Why th are my pants on my head?"

However, I've lately started running into an issue that I can't quite seem to get through... Like at all! It started when I thought it would be a really cool idea to implement a command that makes EVERYTHING invisible for a selected player. You know, the usual everyday kinda' tool needed for proper server administration. But I can't just set all the entities to be invisible with the setInvisible(boolean value) kind of deal, because that would mean that if you had either a hacked client or the entity had some kind of equipment, then you could still see it. I wanted it so that the client that I chose didn't even know the entity existed. So, I initially started by just trying to intercept packets. However, this only worked for vanilla entities, like zombies and basic items. The reason? Because forge is really annoying and decides that it's not going to spawn mod entities through the default channel and is instead going to use an entirely different channel, one that I can't conveniently connect a player entity to through a CustomPacketHandler because this channel remains static throughout the server's lifespan. So I though, jeez, well why don't I just add another CustomPacketHandler to this channel and see how it goes. So I did my first test and tried to prevent an entity spawn packet from being written to the channel. And can you guess what happened? Probably not, because it wasn't a NoClassDefFound exception. Instead, it was a NullReferenceException that lead to an error that said something like, "Don't know how to spawn in this entity." As it turns out, when the packet for spawning an entity is being created, it relies on trying to write the packet to this fml channel and then for some reason it just reads the packet from the fml channel before trying to send it again. So that means if you prevent it from being written then there's nothing that can be read from the channel, so the spawn packet ends up being null. So I though, damn, this is really stupid. So I searched around a bit and found a function called isVisibleTo, which is basically just called to check whether a player can or can't see an entity before it decides to make the packet to send to the player. Then I got an idea: what if I just hijack this function and add some code at the start to make it return false if the player has had this "invisible enemy" command ran on them. So I looked around a little more, and finally, I found out that if you make your mod a plugin, then you can access the transform method of the IClassTransformer interface. Basically, it's like the harmony transpiler patch, but with java! So I got to work.

Now, understand that everything before this point it basically just pretext to give you fellas some good context. From this point on, this is where my struggles are going to start to begin. I started off with writing my hijacking function. It was a static public function with one argument of the type EntityPlayerMP that returned a boolean value. I named this function "canPlayerSee". Now, on the AsmTranspiler end, I had gotten the class/method descriptors and function names from the obfuscated mappings and pulled apart the isVisibleTo function's disassembly. From here, I put together some quick code that injected at the start of the isVisibleTo function the following java assembly codes:

aload_1 //This loads the first, and only argument (excluding the this argument) of the isVisibleTo function

invokestatic //canPlayerSee

ifne //label_0

iconst_0 //This should load the 0 integer

ireturn //This should return the number at the top of the stack, zero in this case

label_0

So I loaded up the server, and nothing bad happened. I run the command on myself to make everything invisible and it works perfectly! So at this point, I'm thinking that this would be a pretty powerful tool if I could load an instance of the Entity that the isVisibleTo function concerns onto the stack and pass is as an argument to the canPlayerSee function for better use. This would let me implement a propper vanish command and a command that would let me turn players of my choice into a creeper that the player in question cannot see. So, I modified the assembly code again. I changed it to this instead: (Note, I did update the canPlayerSee function to accept the new Entity arg at the end)

aload_1 //This loads the first, and only argument (excluding the this argument) of the isVisibleTo function

aload_0 //Loads the this arg to the stack

getfield //EntityTrackerEntry.trackedEntity

invokestatic //canPlayerSee

ifne //label_0

iconst_0 //This should load the 0 integer

ireturn //This should return the number at the top of the stack, zero in this case

label_0

So I launched up the server again... And it crashes: NoClassDefFoundException. This is the error, I am currently getting, and I have tried almost everything I could think of to fix it. Hell, I even tried praying, which almost always works! None of those things I tried are of particular note here, but what is of particular note is the fact that it seems that the crashing will happen only when I make the canPlayerSee function two arguments and change the code to reflect loading the proper arguments. Now, I'm going to send some source code, so just be ready: my chunking skills are horrible and my coding "elegancy" might make you really want to puke. For that, I am sorry. Also, since it's like 3:00 AM rn, I'm just going to try and send images instead of providing text. I know this will make it a bit harder to help, so I am sorry for that too, but I'm really tired.

Nvm, I guess I'm sending text:

This is my entire class for modifying the asm code:

public class AsmTransformer implements IClassTransformer {
  @SuppressWarnings("deprecation")
private static Logger logger = FMLLog.getLogger();
  
  public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (transformedName.startsWith("net.minecraft.entity.EntityTrackerEntry")) {
      ClassReader reader = new ClassReader(bytes);
      ClassNode node = new ClassNode();
      reader.accept((ClassVisitor)node, 0);
      if (analyzeClass(node)) {
        ClassWriter writer = new ClassWriter(3);
        node.accept(writer);
        bytes = writer.toByteArray();
      } 
    } 
    return bytes;
  }
  
  private boolean analyzeClass(ClassNode node) {
		boolean rval = false;
		for (MethodNode method : node.methods) {
			logger.info(method.name);
			logger.info(method.desc);
			if (method.name.equals("isVisibleTo") || (method.name.equals("c") && method.desc.equals("(Loq;)Z"))) {
				try {
					rval = hijackCanSeeFunc(method);
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				} catch (SecurityException e) {
					e.printStackTrace();
				}
			}
		}
		if(!rval)
			logger.info("COULD NOT FIND METHOD!");
    return rval;
  }
  
	private boolean hijackCanSeeFunc(MethodNode node) throws NoSuchMethodException, SecurityException {
		InsnList insnList = node.instructions;
		logger.info("Hackin' it...");

		Method meth = CustomHandler.class.getMethod("canPlayerSee", Entity.class, EntityPlayerMP.class);
		String methDesc = Type.getMethodDescriptor(meth);
		logger.info(methDesc);
		InsnList patch = new InsnList();

		LabelNode ln = new LabelNode(new Label());
		patch.add((AbstractInsnNode) new VarInsnNode(Opcodes.ALOAD, 0));
		patch.add((AbstractInsnNode) new FieldInsnNode(Opcodes.GETFIELD, Type.getInternalName(EntityTrackerEntry.class),
				"d", "Lvg;"));
		patch.add((AbstractInsnNode) new VarInsnNode(Opcodes.ALOAD, 1));
		patch.add((AbstractInsnNode) new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(CustomHandler.class),
				"canPlayerSee", methDesc, false));
		patch.add((AbstractInsnNode) new JumpInsnNode(Opcodes.IFNE, ln));
		patch.add((AbstractInsnNode) new InsnNode(Opcodes.ICONST_0));
		patch.add((AbstractInsnNode) new InsnNode(Opcodes.IRETURN));
		patch.add((AbstractInsnNode) ln);

		insnList.insertBefore(insnList.getFirst(), patch);
		return true;
	}
}

Of particular note here is that last hijack function. The second to last chunk contains the code that inserts my own instructions.

This is the custom function I am injecting at the start of the isVisibleTo function:

public static boolean canPlayerSee(Entity instance, EntityPlayerMP target) {
		if (playerInvisTrollList.contains(target.getName())) {
			return false;
		} else if (instance instanceof EntityPlayerMP
				&& playerVanishList.get(((EntityPlayerMP) instance).getName()) != null) {
			return false;
		} else if (findListElem(Common.creepers,
				index -> index.creep != null
						&& index.creep.getEntityId() == instance.getEntityId()) != null
				&& findListElem(Common.creepers, index -> index.name.contentEquals(target.getName())) != null) {
			return false;
		}
		return true;
	}

I know, it's not chunked like at all. My bad. Also, the findListElem function is basically just the removeIf function for lists, except for instead of removing the element when it matches the predicate, it will just return it instead. It's weird how lists don't already have this function (as far as I know).

Here is the stacktrace:

java.lang.NoClassDefFoundError: net/minecraft/entity/EntityTrackerEntry
        at net.minecraft.entity.EntityTracker.func_72785_a(EntityTracker.java:252) ~[ol.class:?]
        at net.minecraft.entity.EntityTracker.func_72786_a(EntityTracker.java:157) ~[ol.class:?]
        at net.minecraft.world.ServerWorldEventHandler.func_72703_a(ServerWorldEventHandler.java:37) ~[op.class:?]
        at net.minecraft.world.World.func_72923_a(World.java:1222) ~[amu.class:?]
        at net.minecraft.world.WorldServer.func_72923_a(WorldServer.java:1112) ~[oo.class:?]
        at net.minecraft.world.WorldServer.func_175650_b(WorldServer.java:1068) ~[oo.class:?]
        at net.minecraft.world.chunk.Chunk.func_76631_c(Chunk.java:860) ~[axw.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOProvider.syncCallback(ChunkIOProvider.java:109) ~[ChunkIOProvider.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:94) ~[ChunkIOExecutor.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:118) ~[on.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.func_186028_c(ChunkProviderServer.java:89) ~[on.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.func_186025_d(ChunkProviderServer.java:135) ~[on.class:?]
        at net.minecraft.server.MinecraftServer.func_71222_d(MinecraftServer.java:344) ~[MinecraftServer.class:?]
        at net.minecraft.server.MinecraftServer.func_71247_a(MinecraftServer.java:314) ~[MinecraftServer.class:?]
        at net.minecraft.server.dedicated.DedicatedServer.func_71197_b(DedicatedServer.java:270) ~[nz.class:?]
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:486) [MinecraftServer.class:?]
        at java.lang.Thread.run(Thread.java:750) [?:1.8.0_451]

Not much I gotta' say about this.

Here, I even got the disassembled code for the isVisibleTo function in case it helps:

public boolean isVisibleTo(net.minecraft.entity.player.EntityPlayerMP);
    descriptor: (Lnet/minecraft/entity/player/EntityPlayerMP;)Z
    flags: ACC_PUBLIC
    Code:
      stack=6, locals=7, args_size=2
         0: aload_1
         1: getfield      #148                // Field net/minecraft/entity/player/EntityPlayerMP.posX:D
         4: aload_0
         5: getfield      #13                 // Field encodedPosX:J
         8: l2d
         9: ldc2_w        #149                // double 4096.0d
        12: ddiv
        13: dsub
        14: dstore_2
        15: aload_1
        16: getfield      #151                // Field net/minecraft/entity/player/EntityPlayerMP.posZ:D
        19: aload_0
        20: getfield      #17                 // Field encodedPosZ:J
        23: l2d
        24: ldc2_w        #149                // double 4096.0d
        27: ddiv
        28: dsub
        29: dstore        4
        31: aload_0
        32: getfield      #7                  // Field range:I
        35: aload_0
        36: getfield      #8                  // Field maxRange:I
        39: invokestatic  #152                // Method java/lang/Math.min:(II)I
        42: istore        6
        44: dload_2
        45: iload         6
        47: ineg
        48: i2d
        49: dcmpl
        50: iflt          95
        53: dload_2
        54: iload         6
        56: i2d
        57: dcmpg
        58: ifgt          95
        61: dload         4
        63: iload         6
        65: ineg
        66: i2d
        67: dcmpl
        68: iflt          95
        71: dload         4
        73: iload         6
        75: i2d
        76: dcmpg
        77: ifgt          95
        80: aload_0
        81: getfield      #6                  // Field trackedEntity:Lnet/minecraft/entity/Entity;
        84: aload_1
        85: invokevirtual #153                // Method net/minecraft/entity/Entity.isSpectatedByPlayer:(Lnet/minecraft/entity/player/EntityPlayerMP;)Z
        88: ifeq          95
        91: iconst_1
        92: goto          96
        95: iconst_0
        96: ireturn
      LineNumberTable:
        line 475: 0
        line 476: 15
        line 477: 31
        line 478: 44
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      97     0  this   Lnet/minecraft/entity/EntityTrackerEntry;
            0      97     1 playerMP   Lnet/minecraft/entity/player/EntityPlayerMP;
           15      82     2    d0   D
           31      66     4    d1   D
           44      53     6     i   I
      StackMapTable: number_of_entries = 2
        frame_type = 254 /* append */
          offset_delta = 95
          locals = [ double, double, int ]
        frame_type = 64 /* same_locals_1_stack_item */
          stack = [ int ]

This is pretty much everything I can think to provide. I'm not sure what else I can do for you fellas rn, but I hope this can get somebody somewhere. Even if you aren't confident you know exactly what's going on, if you think you have some kind of idea, please don't be shy about replyin'. I would appreciate ANY amount of help here with this, no matter how menial or small it is. Thank you.

  • Author

Oh yeah, and one more thing I forgot to mention. My server runs on Java SE 8 from Graal VM Enterprise Edition. Not exactly sure if this will come in handy.

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.