Posted November 3, 2016 Hello modding gurus. I'm trying to make a seemingly simple mod but I can't get it to work. I'm trying to modify the sendWho method in the LoginHandler class. For now, I just want to change one line of code (but more later). Line 22 of the method looks like this: if (player.getPower() > 0) { I want to change it to this: if (player.getPower() >= 0) { I don't think ExprEditor from Javassist is the way to do this, at least not as far as I can tell. I've tried to hook the entire method to replace it but, since one of the method parameters is a player object, I'm having tons of issues: try { HookManager.getInstance().registerHook("com.wurmonline.server.LoginHandler", "sendWho", "()V", new InvocationHandlerFactory() { @Override public InvocationHandler createInvocationHandler() { return new InvocationHandler() { @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { if (args[0].isUndead()) { return; } Maven complains that args[0].isUndead() is an unknown entity. I'm stumped! Any help? Share this post Link to post Share on other sites
Posted November 4, 2016 this might work in an ExprEditor on the getPower() method: methodCall.replace("$_ == 0 ? 1 : $_"); Another option is to used bytecode: LoginHandler.class sendWho() ConstPool cp = classPool.get("com.wurmonline.server.LoginHandler").getClassFile().getConstPool(); Bytecode search = new Bytecode(cp); ...construct a unique search sequence to match what's in WU. You'll replace this with "replace". Bytecode replace = new Bytecode(cp); ...Construct a replace sequence. CodeReplacer will automatically makes space so the replace string will fit and at the very least completely replaces "search". CodeReplacer codeReplacer = new CodeReplacer(sendWho.getCodeAttribute()); // this isn't valid. I'm being lazy and don't want to look up the steps to get the CodeAttribute for sendWho(). codeReplacer.replaceCode(search.get(), replace.get()); sendWho.getMethodInfo().rebuildStackMapIf6(classPool, LoginHandler.getClassFile()); // this may not be needed. If you get a bunch of weird bytecode errors during server startup add that. And again some of those "get" methods aren't valid. You'll need to figure out the proper steps to get the objects. Share this post Link to post Share on other sites
Posted November 4, 2016 Thanks Joe! But to be honest, I am clueless about the bytecode stuff. I looked at the bytecode for the line of code in question (I think) but it just doesn't make any sense to me, let alone know what to change. For the ExprEditor, the main problem is that player.GetPower() is called several times in this method, and I only want to modify the first instance. Changing player.GetPower() to return a 0 instead of the actual player power (which I believe is what your replace is doing?) would work in the first instance but it would mess up the logic later in the method. I really think hooking the method and modifying it is the way to go, but for some reason it's not working. Share this post Link to post Share on other sites
Posted November 4, 2016 (edited) I'm commenting on how I'd likely do this. I'm sure there are many different ways to do it. sendWho_CtMethod.instrument(new ExprEditor() { @Override public void edit(MethodCall methodCall) throws CannotCompileException { if ("getPower".equals(methodCall.getMethodName()) && methodCall.getLineNumber() == 123) { logger.log(Level.FINE, "sendWho method, edit call to " + methodCall.getMethodName() + " at index " + methodCall.getLineNumber()); methodCall.replace("$_ = $_ == 0 ? 1 : $_;"); } } }); ^^^ the number "123" is fake. You'll need to look at the bytecode to find out the actual number. Using this you can isolate a specific call to a method that shows up multiple times. I think I made a mistake in the previous post for "replace" code and its altered here. I don't blame you for avoiding bytecode. I'm not familiar with Ago's HookManager tool. Edited November 4, 2016 by joedobo Share this post Link to post Share on other sites
Posted November 4, 2016 Thanks again Joe, but I think I have the hook version figured out. I had to instantiate new object and assign the args to the new objects instead of using the args objects directly. A few other kludges to handle non-public methods and everything compiles correctly. Now to test it! Share this post Link to post Share on other sites
Posted November 5, 2016 And, of course, it doesn't work. It compiles without error, but putting it in the mods folder and launching the server gives me this error: SEVERE org.gotti.wurmunlimited.serverlauncher.DelegatedLauncher: javassist.NotFoundException: sendWho(..) is not found in com.wurmonline.server.LoginHandler WTF? The method is there, I've checked with two different de-compiles. I have the signature of the method correct... Is the problem that sendWho is a static method? What do I do in this case? Share this post Link to post Share on other sites
Posted November 12, 2017 Have you been able to figure out a solution to this? I would love for every user to be able to use the /who function. Share this post Link to post Share on other sites
Posted November 13, 2017 maybe take a look at this mod to see how they did it Share this post Link to post Share on other sites