#(advait) Building while pathfinding

198 messages · Page 1 of 1 (latest)

elder peak
#

I asked this question a while ago and fullwall told me I'd need to code it myself, so here's my approach so far:

  • Make a custom trait
  • Make it so that the NPC will navigate normally if it can get to the path via walking
  • Make the NPC build (todo) if it cannot get to the path normally

Here's my approach so far:

    @Override
    public void run() {
        new BukkitRunnable() {
            @Override
            public void run() {
                if (!npc.isSpawned()) return;

                try {
                    Location targetLocation = npc.getNavigator().getTargetAsLocation();

                    if (targetLocation != null && npc.getNavigator().canNavigateTo(targetLocation)) {
                        debugMessage("NPC can navigate to " + targetLocation);
                    } else {
                        debugMessage("NPC cannot navigate to " + targetLocation);
                    }
                    

                    // If stuck or unable to see the target, handle obstacles
                    debugMessage("NPC cannot see target location.");
                    handleObstacle();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.runTaskTimer(JavaPlugin.getPlugin(Mai.class), 1, 1);

the handleObstacle(); code will be written later to handle the actual building

however, canNavigateTo running every tick is extremely computationally expensive, my server is basically unplayable with that code. is there a more elegant way to do this? i want to make sure im not overcomplicating it

full cometBOT
#

(advait) Building while pathfinding

full cometBOT
#

Hi I'm AutoThreadBot! Don't mind me, I'll just be adding the helper team to this thread so they can see it. A human will get to you soon.

thin fable
#

yes pathfinding checks are expensive so why not give it more delay?

elder peak
# thin fable yes pathfinding checks are expensive so why not give it more delay?

well if i gave it more delay that'd cause some more issues i'd imagine?

as an example, let's say i want the npc to build towards me and i give the runnable a delay of 10 seconds. that means it'll build one block towards me, not be able to get to me, and then have to wait another 10 seconds before building another block towards me

#

this plugin https://github.com/notnotnotswipez/TerminatorNPC/blob/master/src/main/java/me/swipez/terminatornpc/trait/TerminatorTrait.java basically checks for every edge case (e.g. when to bridge, when to mine, when to tower) based on the target's location and proximity from the npc, but is that really necessary? is there no simple way to just see if an npc can/can't get to a location without it being computationally expensive?

GitHub

Contribute to notnotnotswipez/TerminatorNPC development by creating an account on GitHub.

thin fable
#

just try 10t?

#

1t is too short

#

and at least 1t is needed for Citizens to update path

thin fable
#

I'll have to go for work, leaving this to someone else or I'd happy to talk about this when I'm free.
20- min to 7 o'clock for UTC+8

elder peak
#

ill look into it while you're busy too ofc

elder peak
#

the citizens config by default says the pathfinding only gets updated every 1 second, do plugins override that? or do i have to change it in the config as well?

elder peak
#

testing with this code

                    Location targetLocation = npc.getNavigator().getTargetAsLocation();

                    if (targetLocation != null && npc.getNavigator().canNavigateTo(targetLocation)) {
                        debugMessage("NPC can navigate to location.");
                    } else {
                        debugMessage("NPC cannot navigate to location.");
                    }

something super strange i found is that the server basically doesnt lag when the npc can navigate to its location, but as soon as it has no path it lags out. that makes no sense to me, am i missing something? why would it suddenly start lagging when the same function is being called regardless

heady saddle
elder peak
#

right now the citizens config (and my code) use the new pathfinder

#

im not against using the new pathfinder because i believe its better than the old one; is there any way to make it not lag out the server?

#

this is all very new to me so sorry if some of my questions seem trivial

#

the issue is when i use the old pathfinding its claiming the npc can still navigate to me when it obviously cant lol

heady saddle
#

You could adjust how many blocks get checked for a path

elder peak
elder peak
#

and also why it keeps switching between the two, like theres no path there, what is it doing?

heady saddle
heady saddle
elder peak
heady saddle
#

From memory, minecraft will look at 768 blocks before giving up

elder peak
#

alright lowering the values definitely helped but the pathfinding (using newer citizens pathfinding btw) does get significantly worse as you lower said values

#

wondering if theres a sweet spot

elder peak
#

path debug helps btw, its basically showing that whenever the npc has an option of getting closer to me, canNavigateTo is true. but that doesnt make any sense to me, shouldn't canNavigateTo check the entire path holistically? why would citizens think that the path is possible just because the bot can get a little closer?

elder peak
elder peak
#

i remember a while ago you talked about using BlockExaminer to help with this, is that applicable? im not really sure how to use it

elder peak
#

okay, after some further debugging, here is what i found:

                    if (targetLocation != null && navigator.canNavigateTo(targetLocation)) {
                        debugMessage("NPC can navigate to location.");
                        return;
                    } else if (targetLocation == null) {
                        debugMessage("NPC target location is null.");
                        return;
                    }

                    // This is where the code gets spicy
                    debugMessage("NPC cannot navigate to location.");

using this code, it turns out the only two possible cases are "NPC can navigate to location" and "NPC target location is null." there's never a case where the NPC cannot navigate to the location but also has a non-null target location.

my question is... how is that even possible? why is that target location getting nullified whenever theres no path? it clearly remembers where it needs to go because, once a valid path is built, it locks back onto the target

heady saddle
heady saddle
#

canNavigateTo does remove existing paths if you're using the minecraft pathfinder

elder peak
#

what ive basically found from testing for the past few hours is that:

  • none of the issues above are present when using the a* pathfinder (meaning, if it cant get to the path, canNavigateTo will actually return false)
  • using the a* pathfinder (expectedly) is much laggier
#

is my approach wrong? like, is there a simpler way to do this than constantly checking canNavigateTo in my trait?

elder peak
#

the actual target is just whatever i set it to be, e.g. if i do /npc follow the target will obviously be me, if i do /sentinel addtarget zombie the target will be the nearest zombie etc

#

the really strange thing though is that when i run this code:

    @CommandAlias("ispathpossible")
    public void runIsPathPossible(Player player) {
        NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(player);
        if (npc == null) {
            Messages.sendMessage(player, "&cYou have no NPC selected!");
            return;
        }

        long startTime = System.currentTimeMillis();
        boolean canNavigateTo = npc.getNavigator().canNavigateTo(player.getLocation());
        long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;
        Messages.sendMessage(player, "&aResult for path: " + canNavigateTo + " (" + elapsedTime + " sec)");

    }

it always takes 0 seconds to run, it runs instantaneously. but its using the same exact method, why is it only becoming an issue when im doing canNavigateTo in the trait? is it just because its running so often?

elder peak
#

for whatever reason the minecraft pathfinder just always thinks the npc can navigate to a location

#

the more i experiment the less sense it makes 💀

heady saddle
#

looks like there was a bug with minecraft navigator canNavigateTo, you should download the latest build

elder peak
#

but also, would that be less laggy than a*? im still a little confused on how theyre different

#

does the minecraft pathfinder not check as many paths as a* does?

heady saddle
elder peak
#

just did

#

however

#

i dont think the fix worked

#

because this should be saying can't navigate

#

it occasionally flickers and says cant navigate, thats when the server lags out

thin fable
#

just wondering if it saying so is vanilla behaviour

elder peak
#

like i said before, im not against using a* if there was a way for it to not lag out the server. im just confused on how when i run the command to test a* myself theres no lag but when its ran in the trait method there is lag

elder peak
#

because a* is always accurate

#

at least, from my testing

#

its mc pathfinding that causes the canNavigateTo issue

thin fable
#

the reason I say so is that, for example, will a zombie cancel its navigation to you even you are 3 blocks higher than it?

#

ofc not as zombie will just keep walking

heady saddle
elder peak
#

yup, i have a feeling its an issue with mc. even the command is saying it can navigate

heady saddle
#

minecraft will ignore air blocks and move the target to the highest ground Y

elder peak
#

so i guess i have to use a*

thin fable
#

and also, it is tough to make canNavigateTo return false for MC navigators

elder peak
#

which is fine i just dont know how to make it not lag, even when i drop the iterations all the way down to 50 its still unplayable

thin fable
#

as that is vanilla MC

heady saddle
#

pathfinding every tick is not recommended for a reason

thin fable
#

!spark

chrome stirrupBOT
# thin fable !spark
Info: spark

The "timings" system within Spigot/Paper is incredibly inaccurate for use with Citizens, and cannot be used to diagnose any issues related to Citizens. It notably blames Citizens for a significant amount of entity-related lag (that isn't in any way caused by Citizens).

For accurate timings, you need a Java profiler. There are a variety of profiler options (WarmRoast, YourKit, VisualVM, ...), but the simplest to use on a Spigot server is a plugin named "Spark" that embeds WarmRoast, which you can find here: https://www.spigotmc.org/resources/spark.57242/.

To get a spark report, type /spark profiler start, then replicate lag issues (for no more than about a minute), then /spark profiler stop, and post the link it gives you.

elder peak
#

got it will send rn

elder peak
#

let me show you right now

#

im going to set the repeat time in the run function of my trait to 40 ticks (2 seconds)

#

and run a spark report

#

here

#

thats running every 2 second at the default iter values in the citizens config

elder peak
#

thats what im doing right now actually

#

and just to prove it, here's my spark report when just spamming the command above multiple times per second: https://spark.lucko.me/k7KBkTBG6r

so something is up, i just dont know what

spark is a performance profiler for Minecraft clients, servers, and proxies.

thin fable
#

might be related to NMS -> OBC object wrapping as so many block state OBC objects are created

#

unfortunately that's what we can't handle from Bukkit API side, might need some deep dig on this. maybe we shouldn't use Bukkit API for pathfinding?

elder peak
#

i mean we're not using it though for pathfinding i thought? im exclusively using citizens's new pathfinder, is that still part of the bukkit api?

thin fable
#

I think that should be solved on Citizens side

#

ofc not as Citizens have its own API

#

I'm just saying about ideas that I have for improving on this

thin fable
#

most of the time in that report is used to wait for next tick

elder peak
thin fable
elder peak
#

the "runnable" being the overridden run function every custom trait has

thin fable
elder peak
#

you'll find this interesting, the time elapsed is still saying 0 seconds for calculating the path even in the trait class (code just to make sure im not going crazy)

                    long startTime = System.currentTimeMillis();
                    boolean canNavigate = navigator.canNavigateTo(targetLocation);
                    long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;

                    if (targetLocation != null && canNavigate) {
                        debugMessage("NPC can navigate to location. Target type: " + navigator.getTargetType() + " (" + elapsedTime + " sec)");
                        return;
                    } else if (targetLocation != null && !canNavigate) {
                        debugMessage("NPC cannot navigate to location. Target type: " + navigator.getTargetType() + " (" + elapsedTime + " sec)");
                        return;
                    }
thin fable
elder peak
#

yeah im wondering too

#

i mean it surely must be me doing something wrong on my end right? because a* pathfinding has been a thing in citizens for ages and im sure the code uses canNavigateTo multiple times, its not supposed to lag the server out like this

thin fable
#

I think that's not your fault

#

or... both of us have something went wrong

elder peak
#

im just hella confused on why the first spark report is so much more intensive than the second

heady saddle
heady saddle
#

Just snippets

#

Or your config.yml

elder peak
#

i can provide both

#

give me a sec

#

is there anything else i need to send?

#

pretty much all the relevant code is in the java file

elder peak
#

still though, 9-10 ms average when the server is lagging

#

sorry for spamming so many images but i also just wanted to confirm we're on the right build of citizens as well

neat grottoBOT
elder peak
#

this may actually be one of the most confusing coding problems i've ever seen

thin fable
#

I also have no idea currently

elder peak
#

wondering if fullwall may know whats up, i really dont know

#

@thin fable i think i found the problem...

thin fable
#

wHaT?

elder peak
#

bro i have no idea

#

how is that even possible

thin fable
#

I was remembered that interesting silly "if" which ran for 1 million times in a sec in somewhat game

elder peak
#

does 40 ticks not equal 2 seconds

thin fable
#

ha

thin fable
elder peak
#

what is going on

#

i need fullwall back 😭

thin fable
#

Either fullwall and I can't do anything without spark reports and you latest code

#

and feel free to use our paste

#

!pastejava

chrome stirrupBOT
elder peak
#

i gave you both already no?

thin fable
#

any updates to them?

elder peak
#

no not at all

#

except that print statement

#

i can run again if you want but it would have identical results

#

i mean we found the issue

#

the question is why is that even happening

#

i dont even know what this means

#

am i overriding something thats making it run every tick?

thin fable
#

traits are ticked for every tick, that works as intended isn't it?

elder peak
#

then whats the point of the runnable

thin fable
#

but the runnable shown in your code is not used by your trait?

#

oh

#

yes you created the runnable in trait tick

#

what the hell

elder peak
#

wait am i not supposed to put a runnable inside of it

thin fable
#

yes

#

if you put runnable in ticks then you'll get more and more tasks ran on your server

#

it is impossible to have no lag

elder peak
#

bro why is there even a runnable there

#

when did i put that there

#

oh im actually an idiot then

thin fable
#

IDK why you're asking me about your own code

elder peak
#

that means its making a new runnable every tick which repeats itself every 2 seconds

#

no wonder its lagging

thin fable
#

yes

#

you created repeat runnables every tick and they never dies

elder peak
#

i swear i saw somewhere you were supposed to put a runnable inside of it idk why 😭

#

let me remove that then

thin fable
#

you should move it to somewhere like onAttach

#

and cancel the task onDetach

elder peak
#

im assuming its still going to lag even with it removed though

thin fable
#

hmm I think onSpawn is better to place tasks

elder peak
#

bc its still every tick

#

ohh

#

you mean like put the runnable code in onSpawn or somewhere like that

#

i see

thin fable
#

I recommend onSpawn as it only calls when NPC spawns and navigator should be available for use at this time

elder peak
#

i agree let me test that

thin fable
#

so you don't have duplicate and infinite garbage tasks

thin fable
elder peak
#

yea ofc

thin fable
#

so funny and time-wasting as I've not read your code carefully lol

elder peak
#

works perfectly even when running every 10 ticks

#

thank you so much i have no idea how i missed that

thin fable
#

lagging is solved so... next question is about MC impl for canNavigateTo, maybe we'll have to leave this to fullwall

elder peak
#

yup, i think fullwall can take a look at that when he wants, assuming it even needs fixing. but personally i think the name is misleading

#

if that does work as intended i would at the very least change the method name

#

thanks y'all, going to close this thread but ill definitely be back lol. working on a massive project that uses citizens so im sure ill have more questions

thin fable
#

that's ok! feel free to ask question when you need

#

you can close this if you're all good