Resource Maven & NMS tutorial

Discussion in 'Spigot Plugin Development' started by Sataniel, Nov 13, 2018.

  1. This is how I have it laid out,

    Not sure if I have any files in the wrong place?


    I'm unsure of inside the parent pom, what am I meant to replace this with?
    Code (Text):
    #21 Sean0402, Dec 29, 2019
    Last edited: Dec 29, 2019
  2. If building the project to fetch the dependencies doesn't work, then I don't know. I don't use IntelliJ, but I don't think Maven projects are supposed to have .iml files in it since they to my understanding do what the pom.xml is supposed to do: Store dependency information of the module. So the dependencies might be taken from the .imls instead? In NetBeans, you'd choose the type of the project (e,g, Java program, Maven jar project, Maven pom project, ...) when it's created. This might be wrong here.

    About the folder structure, it looks wrong to me that a "src" folder is at the same level as module names. The source is inside a module.

    Whatever your dependencies that are meant for the whole project are.
  3. I may have figured it out. 1 last question, which pom am I compiling? Is is the dist one? Assuming that since it's named after "Distribution". Sorry for asking so many questions. Complete noob to maven stuff.
  4. You can build each module separately. Building the parent builds everything.
  5. This works...
    But it's not ideal.
    Firstly, it's extremely inconvenient to use abstraction and have to import every single version.
    Secondly, reflection is much easier.

    As for your performance argument, there are ways around that. Take a look at NoReflection. Nesaak has managed to make reflective calls faster than inline Java.

    Abstraction is a waste of time for something that has this many implementations. I highly suggest you look into this; the usage is very simple. Cache the DynamicCaller or FieldAccess in a static field (making one costly call to get that object in the first place), then whenever you need to invoke something just call whichever method you need.

    As for checking which version you're using, look into a class like this.

    I completely disagree with your post.
  6. That's a pretty weird claim to try to make. I'd very much like to see the source of those benchmarks - depending on how they are being run, the JVM may be running behind-the-scenes optimizations that are then not being reported, yielding unrealistic results. Even if they are actually accurate, because you're very unlikely to see 10 million subsequent calls to the same exact NMS method by a plugin in a real world scenario, the results may well be completely useless and inconclusive due to how diluted they are.
  7. OP takes care to address your objections in the first post, so I would suggest you revisit it if you have not already.

    Even if what you claim is true, there are still other reasons why Maven abstraction should be preferred over reflection. Maven abstraction for NMS/OBC has been around for nearly a decade, so the bar for selecting an alternative method of ensuring portability is much higher than asserting that you can write equally fast code.

    It really isn’t.

    The work you need to do for reflection and abstraction is pretty much the same in the worst case if you need to update method and field names.

    Otherwise, if things stay the same, you basically copy/paste, text replace the imports and add a new version case in your onEnable().

    In addition, the pure fact that something inconveniences you is an invalid rationale for not doing it if you get a net benefit as a result. It inconveniences me somewhat to write clean code, but I don’t use that to justify writing garbage code because it is worthwhile to trade minor inconvenience for a benefit.

    These numbers are very close to meaningless (if not likely to be outright wrong). However, I’m not going to bother continuing to critique them because performance is the weakest reason to prefer abstraction. Truthfully, reflection is not all that slow anyways and there are multiple robust ways to make it faster.

    The point is, the main purpose of abstraction isn’t performance. It is only a perk that you have fast code by default. Again, OP explains the purpose of abstraction perfectly clearly, so don’t take it from just me.

    Using reflection doesn’t preclude you from needing to write boilerplate; in fact, there are good reasons to think that writing reflection is even more cumbersome and problematic than abstraction. No compile-time error checking, exception handling, caching and readability suffer when using reflection, among others.

    Regardless, in principle, it is incorrect to use reflection for the purpose of portability. The main problem of reflection is that it relies upon the runtime to provide compile-time characteristics, so something that the code wasn’t actually meant to work for still ends up causing issues. In practice, this is not very common, but again, the principle of using it for this purpose is in direct violation of what reflection is intended for.

    Declaring your disapproval of abstraction without clearing the absolute minimum bar of understanding its validity makes this statement comically lacking in tactfulness.
    • Winner Winner x 1
  8. I stand by my opinion, but I apologize for not seeing that the first time. OP did address my objections in the original post.
    There are pros and cons to both, but having to build every single version of Spigot, and then proceed to make modules for each, is time-consuming, to say the least.

    Having multiple versions of each class that uses NMS, with most of the code being identical, is a "minor inconvenience"? I'd say having a few if statements is easier.
    As for readability? Reading code that utilizes reflection is a bit harder than reading plain code, but someone who has a decent understanding of Java and reflection should be able to read it without much extra effort. Well-documented code is future-proof.
    If someone doesn't know how to use reflection then they probably shouldn't be dealing with NMS.

    Regardless of what method you choose you still have to: test your code on every version it supports, read through the docs, and look through the obfuscated code.
    Although it may take more time to write the actual code, you save time by not making eight copies of the class.

    That is uncalled for.

    I'm done arguing; I've made my point against OP, you've stated your position, siding with OP, and now I'm making a defence.

    The whole point was that it's faster than normal reflection. I'm not saying that you should be comparing it to inline code, just that there are solutions for reflection performance.
  9. I don't think you read my reply.
    If optimizations are being applied, the "invocation" may in reality be doing nothing because the entire content has been skipped due to dead code elimination.

    You should read about proper benchmarking before blindly agreeing with numbers without context. I suggest for a basic understanding.

    Edit: To clarify, my point isn't whether or not the library is faster than inline code, it's that if the result of one comparison (namely library vs inline) is fishy, then all of the other comparisons are also fishy. There is no evidence that the library is faster than ordinary reflection because the benchmark used appears to be flawed.
    #30 Jikoo, Dec 7, 2020
    Last edited: Dec 7, 2020
  10. Yes? It takes me at the very most a few minutes for a major release every so often. The most difficult part is Ctrl+C, Ctrl+V, Ctrl+R class names and Ctrl+R import versions. It isn’t all that difficult or time-consuming. The fact that most of the code stays the same is what makes it easy to update.

    As far as writing the code in the first place, I’m sure can agree there’s no competition between the two.

    The fact that reflection is more difficult to read/write/understand has little to do with your knowledge of reflection itself. The main reason why it is difficult is because of indirection. The content of what the code does is not located at the method call, it is hidden behind a generic accessor that has no compile-time parameters or concrete return types. Accessor constants also must encode class and method signatures. Writing reflection calls start to get out of hand really quickly when you start moving beyond trivial use-cases.

    I don’t understand what the point is about documenting the code, it applies in either case without really changing the fact that it simply is more difficult to sift through lots of reflection calls.

    I really don’t know how good of a grasp you have on updating NMS/OBC modules, but as I keep on badgering you about, it isn’t so much of a hassle that it is worth using reflection.

    It almost makes me believe that you are doing something really wrong if copy/pasting code poses such an important issue to you that you’d rather avoid it, so I’m curious to see how long it actually takes you.

    So, something must have called for you to “completely disagree” with OP, right? The point is that you address the weakest reasons why you should prefer reflection to induce the opinion that the OP should be discarded in its entirety. It shows a lack of respect for OP and a severe lack of tact.

    I don’t really think this is a productive discussion to have, but the point is that there are valid ways the overhead of reflection can be fixed, even if not through the specific library mentioned.

    Again, reflection isn’t even all that much slower in most cases, and the benefit of using a raw call against reflection is pretty small. Performance alone doesn’t really seem like a compelling reason to choose abstraction or reflection under most circumstances.
    • Agree Agree x 1
  11. That's fair, you're correct. Probably too far off topic, I'll refrain from further discussion in that direction.
  12. That's fine. Do what works best for you, the developers you work with and your project. For the reasons the thread explains, my experience is that the more a project relies on internals and the more different versions you're supporting, the more does abstraction improve maintainability. I don't think abstraction is much work; it's not that different from making a branch in Git and applying your changed to it, which means it's about as much "paperwork" as you'd usually have for any medium-sized new feature. It's just a different command or a few different clicks in a different UI.
  13. Do we need to own a server for this (for NMS modules, and project itself).. to compile everything? :unsure:
  14. No - you can install artifacts locally. BuildTools takes care of this for you when run, but if you want to manually install a file it's certainly possible.
    Code (shell (Unknown Language)):
    mvn install:install-file -Dpackaging=jar -Dfile=mycoolplugin.jar \
       -DgroupId=com.example -DartifactId=coolplugin -Dversion=1.0.0
    mycoolplugin.jar would then be installed to com.example:coolplugin:1.0.0, so you'd be able to use it like this:
    Code (XML):
    That said, installing files locally reduces your portability (which is a major point of using a dependency management solution) so you should look to avoid it where possible. If you really must use them you should consider writing a small script to download and install the files if possible. For NMS, this would be a script that downloaded BuildTools and built the relevant versions.
    • Informative Informative x 1
  15. Thank you very much for this. This is HUGE help, recently i even tried to learn Maven usage, and like "everything Maven related" just because of this.