Need a little help understanding children commands and such

Hi there, as the title states, I’m having a little trouble understanding how to set up children commands for a main command.

Basically, I have a main /cd command that can accept 34 different arguments (obviously the different arguments display different data), but I can’t seem to wrap my head around how to set up the main command to accept the arguments as…well, arguments. Like, if I wanted to type /cd <arg option 1>, how would I configure that in my plugin so it works properly? Using the .arguments specifier in the CommandSpec, or…?

Thanks to anyone reading this in advance!


Largest note here is that an argument is different than a child command (I’m of the personal opinion that this differentiation isn’t well defined in some ways). If you have arguments, they would go within CommandSpec#arguments. For children, CommandSpec#children (which accepts a CommandCallable, generally another CommandSpec.

If you need further assistance, please include the code you’re trying within a block or gist (best for larger excerpts).

Decided to save the commands part of my plugin for last.

But, perhaps, by looking at this, you can tell me why it doesn’t work? No errors, no “not at that location” debug message, no nothing. I’m hopelessly confused on this one. I need this function to work. I need my Sponge replacement for Skript’s “on walking on”. XD

(When it gave me an error saying I needed a return statement, I’ll be honest and say I have no idea what it wanted me to return so I just stuck whatever I could in there so it would stop giving me the error)


This is a lot wrong with this; I don’t even know where to begin and I’m not going to make an attempt to. I can help where possible with Sponge related questions, but I will not try to redesign your code. You need to review Java/programming fundamentals before working with Sponge, and when you’re ready begin working through the Sponge Docs.

At a guess, you’re someone who has never programmed before and has only ever worked with Skript. Skript is nice for some things, but it is no substitute for a language - if this is the case, you are definitely in over your head for where you are now.

(I have been reviewing Java fundamentals and the Sponge API and, as stated in my other post, I’m new to the Java world)

While I appreciate the constructive criticism, everyone telling me I need to “go back and look at the Sponge docs or watch plugin tutorial videos” when I can’t figure something out is only mildly helpful. Everywhere you’ll look on the Internet for Sponge/Java tutorials, you will find very basic “hello commands” or “hello plugin” tutorials. Trying to take what they show and apply it to what I’m trying to do would be like trying to make a philosophical explanation of 2+2 (taking a simple example and applying it to a much more complicated situation).

Never did I ask you to “redesign my code”. I simply asked why it was not working based on what you could see in that screenshot.

As a Skripter who is trying to become a Java-er, these type of comments on our posts asking for advice on why our Java coding is not working is why we Skripters would prefer to stay Skripters.

Nevertheless, I do thank you for your time. Telling me that there is “a lot” wrong with the code in my screenshot is the most helpful thing (and, if I may be completely honest, the only helpful thing) you have said.

Moving on, how is your work on your plugin you were working on that we were once discussing in our private Discord chat going?

I cannot tell you specifically why it doesn’t work because I have no idea what the context is behind its operation, how the method is being called, and what in particular doesn’t work. If you wish for me to point out some of the specific issues I can note some of the major flaws.

  • An event listener should be an instance method (non-static), return void, and have a single Event as the first parameter followed by any number of related event filters. Listeners are generally named onEvent, and should not create or return an Event. See Event Listeners — Sponge 7.2.0 documentation
  • Retrieving an Entity named player is sketchy, as it implies that it is an instanceof Player - if this is the case, then it should be cast and stored as a Player. You are also recursively calling this method multiple times, so if it did run it would throw a StackOverflowError right from the start. You also do this at the end for some reason.
  • Creating a different Random object is a waste of resources and an improper use of the class. It is designed to be pseudo-random, so it will represent the expected distribution of values faster than an actual random number generator would. You should be reusing the same instance for each call.
  • You should not generate your values until you actually need them. In the given code, none of value, route1Kanto, or shinyPoke are used if the if statement is false. They should not be generated until the last possible moment. Additionally, the Random class also have methods like nextBoolean for convenience.
  • The use of hardcoded values is a huge flag and will become worse and worse the more checks are added. I personally would create an object responsible for spawning at a given location and store it in a HashMap<Location<World>, MyObject> map - this is both clearer and is much closer to O(1) performance.
  • Processing commands like this should only be done if the command was user-inputted somewhere else, as you have no other option. If you control the command, you should implement that command programmatically using the necessary APIs. In your case, this should be something defined in a config file that you can edit without touching the plugin which is a valid use of #proccess; just understand the consequences of running a command from the server (no permission checks).
  • Anytime you see sections of code that look similar, you should think to yourself, “There’s probably a way to simplify this” - 99% of the time, there is.

I keep an eye on the forums and discord to help people out who are having difficulty with Sponge as I’ve been there myself (and often still am with new projects). However, there is an expectation that you are comfortable with the core concepts of Java - I can’t begin to explain how to properly use things like the command API or event listeners if people don’t understand the constructs that make them work. The focus of any support here should be Sponge based as the related Java information is available in many tutorials and sites (and often better explained than many of use could do).

On your note, I’ve done work with finalizing a language syntax that takes inspiration from a handful of common programming languages like Swift, Ruby, Kotlin, Python, and Lua (plus Java - but primarily what not to do .-.). This is still more of a hobby project of mine, so no guarantees on when it’d be complete - or if it will.

1 Like

Basically, that code there is supposed to trigger every time the player walks over the block that has it’s coordinates hard-coded into the plugin (hard coded only for testing purposes to see if the code would actually trigger). It’s the only thing in the Sponge docs I have seen (after doing multiple searches) that closely replicates Skript’s ‘on walking on’ function.

The code is supposed to have a 3% chance of triggering, with rngs deciding what happens (what Pokemon is spawned basically) if the RNG picks the number that says “run the spawn code” basically. So, to avoid having the issue of can only spawn if the 3% chance fires, we have that block capable of spawning any Pokemon that appears in that area. The last RNG used is for deciding if the Pokemon that is spawned is spawned in it’s rare ‘shiny’ form, which is why the RNG for that one is set to 1-8192. As inexperienced with Java as I am, even I can see that there are better ways to write this code. This is as simple as it can be written, I would think. If I had used variables instead of hard-coded it, I would have came across the issue of wondering what wasn’t working (variable a, variable b, variable c, or the whole code in general, etc) and would have spent longer trying to discover what wasn’t working.

I noticed that the MoveEntityEvent wasn’t listed with the event listeners, and I found that as strange because, according to the Sponge docs, it get called when an entity makes a move, so it should have a listener, I would think.

I set the entity to player because I need the code to only execute when a player steps on the block, and I couldn’t figure out any other way to convert from ‘Entity’ to ‘Player’.

So, if this won’t trigger on it’s own, what can you (nicely please :P) suggest I should do to get it to trigger just so I can test it?

I’m not sure where you got your method signature from - because it looks like you want to create the event, not listen to it there!

Change your first line (under listener) to:

public void onMove(MoveEntityEvent event, @Root Player player) {

and then remove your Entity player... line and your return at the bottom. You’re not interested in creating the event, you’re interested in listening to it.

Remember, as far as listeners go:

  • They must be public and return void
  • They must contain an event as the first parameter
  • They can contain event filters, which are the second onwards parameters which are all annotated.
  • They must be registered unless it’s in your plugin class, so in your main class in one of your init events, you need to register the class with Sponge.getEventManager().registerListeners(<plugin object>, <listener object>); - plugin object is this in you are in your main class.

See Event Listeners — Sponge 7.2.0 documentation in the docs for more info. Hope this helps!

Wonderful! It works now. Thanks to both of you, so much!

There’s this, but I need to check for if a player is between loc1 and loc2, not getting the distance between loc1 and loc2, and all the Sponge docs have to say about distance is fall distance. Any method I could use?

Would mean manually setting location 1 to a location in the coding, manually setting location 2 to a location in the coding, then checking to see if the player is between those two locations. (Basically, making an invisible box and checking to see if the player is in the “box”).

Thanks in advance!

Never mind. I have a pretty good feeling I can accomplish the same thing by doing this:

public void onMove(MoveEntityEvent event, @Root Player player) {
CommandManager cmdManager = Sponge.getCommandManager();

    Location<World> loc1 = player.getLocation();
    Random rand = new Random();
    int value = rand.nextInt(3) + 1;

    Random shiny = new Random();
    int shinyPoke = shiny.nextInt(8192) + 1;

    // Route 1
    if (loc1.getBlockX() > -1253) {
        if (loc1.getBlockX() < -1289) {
            if (loc1.getBlockZ() > -1639) {
                if (loc1.getBlockZ() < -1711) {

Soooo, yeah, before I can check to see if my method above ^ there is actually something that is going to work, I need to get Java to stop derping.

^ This wonderful thing here…
Well, its not working. Much to my annoyance, it tells me that I am not walking on stained hardened clay when I know for a fact that I am. It instead insists that I am walking on air.

Halp? XD

Well, the player’s location is the location of their legs. So your legs are currently in air, even if the block under them is stained clay.

Location loc2 = loc1.sub(loc1.getBlockX(), + 1, loc1.getBlockZ());

I used this to get the y-coordinate equal to the y-level of the block (confirmed this by having it print the value of the updated y-coordinate to my console) but it still says that I’m walking on air.

That would still be off because you’re subtracting out the x and z values - it’s giving you (0, some y, 0). You’re looking for loc1.sub(0, 1, 0).

To note an implementation detail, just recall that BlockTypes is a CatalogType, not an Enum. This comparison should work fine as there shouldn’t be multiple instances of a BlockType, but just know it doesn’t have the same semantics - depending on your preference, .equals() may be preferred.

Oh, sweet. That made it work. Thanks! But, now that its working, I’m faced with a new problem…

Its running the code when I even move my mouse around to change my point of view. Standing perfectly still. How can I make it not do that?

Oh, and its being triggered by other entities as well. That’s not good. But, I think I know how I can fix that.

Rotating counts as moving. If you don’t want to trigger when entities move, you should check the getFromTransform and getToTransform and see whether the actual location changed.

Meanwhile, the people above are correct. You really need to read over the docs. If you had, you would never had that crazy event signature in the first place.

I’m more of a “learn by doing, failing, and being told how I failed” kind of learner. I could spend more time reading over those documents and still not know what I’m doing. I could watch every plugin/Java tutorial on YouTube and still not have the slightest idea what I’m doing. I learn by doing, not by reading, but I appreciate the advice.

I understand that, I really do. But it gets incredibly frustrating for someone to ask us all these questions, when the answers are perfectly clearly outlined in the documentation. Reading the docs might not teach you all there is to know about Sponge programming, but when you run into a roadblock, you can remember ‘hey, that’s in the docs!’ and go back and look it up. It’s certainly easier for everyone else if you do, instead of jumping straight to the forums, with crazy code that I have no idea where you got. For example, the event documentation that @dualspiral linked, had you read it, would have told you exactly what you were doing wrong. Think of looking for the relevant topic in the documentation like asking a help question, except nobody will tell you off for not reading the documentation. Because when you say that you need someone else to tell you what you did wrong, you’re essentially shunting all the effort of learning onto us.

He provided the answer with his reply, so there was no need to visit the page in his reply.

Moving on, when I ask for help, I don’t ask to have you guys do my work for me. If you notice, my questions usually include “what do you suggest” or “why doesn’t this work”. I’m not asking for the answer I need to make my code work. I’m asking for why it doesn’t work so I can take the responses and try to piece together what I need to do. If the reply just so happens to contain the answer I need to make my code work, then yay for me, but I don’t expect nor do I ask for the answer. I would be perfectly content with a link to the proper documentation page as a suggestion for what I could use, or a simple “use this method with the other stuff that you need to look up” stuff like that.

For the same reason I provided the link in my response above, dual included it again not only because it contains accessory information and examples but also because you need to be familiar with referencing the docs for information. I am much more willing to help someone knowing that they have attempted to solve the problem on their own using the available resources. Our goal is to identify specific issues and point you in the right direction, not to repeat what’s already on the docs.

The reason why it doesn’t work is that you’re not using Java or the API correctly. I would suggest reading the Oracle Java Tutorials, the Javadocs, and the Sponge Docs, the Sponge Javadocs (which are also easily available through your IDE). Sites like Stack Overflow can also be good for reference, but they’re even more particular about doing your own research first than we are. So far, most of your questions have been based on topics that are well documented or could be handled through some simple debugging. As a result, it appears as if you don’t do any research or testing on your own before asking for help - and that makes others less willing to assist in turn.

1 Like