#gameplay-ai
1 messages Β· Page 172 of 1
Hi guys!i'm using AI sight perception on my character to detect objects it can interact with. Right now it perceives all kinda of actors, what is the best way to perceive only actors which implement a certain interface or with a specific tag?so that when i call getPerceivedActors i already have them filtered out
There's a Mass channel on this discord server, suggest you ask there. Plenty of people using it for RTS over there too.
There's nothing like that builtin really. The only option is to not have the actors you don't want seen exist in the perception system. You can simply do this bookkeeping yourself, it's not that complex
How do i exclude actors from the perception system?
only pawns register by default with it iirc, and they should have a setting that you can change to turn it off
I see thats's way it only saw the player, thank you very much!
Per player, I have one pawn and one AIController. I want to create & attach a new aicontroller + pawn to any new created PlayerController, but I am having some troubles. What is the recommended way for this?
Right now I basically unposses & spawn an ai controller in the pawn in BeginPlay and tell the original controler the ai instance
But it seems sometimes there is no controller at BeginPlay for the pawn, probably because it is still being assigned from GameMode::SpawnDefaultPawn
You can use On Possess or Possessed or whatever the event was to detect when one is assigned
I thought so as well, but the function in the GameMode uses SetPawn() which doesn't seem to trigger an "OnPossessed"
at least it didn't for me
(the default function)
Are you doing this logic within the controller?
I tried various locations, currently it's in the pawn
Maybe I should just disable auto-spawning and create the pawn manually
Odd, it definitely should get possess called at some point
But yeah you could manually spawn either the pawn or controller
NewPlayer->Possess(NewPlayer->GetPawn());
out of curiosity I looked at the gamemode logic, it definitely does possess :)
this happens in FinishRestartPlayer which as far as I can tell is always called when a new player is spawned and has its pawn assigned
Hu
Where is that line?
For me it just says
else if (GetDefaultPawnClassForController(NewPlayer) != nullptr)
{
// Try to create a pawn to use of the default class for this player
APawn* NewPawn = SpawnDefaultPawnFor(NewPlayer, StartSpot);
if (IsValid(NewPawn))
{
NewPlayer->SetPawn(NewPawn);
}
}
it's further down from that
although it looks like yours is different from mine ever so slightly, I'm on 4.27 so not sure if it's different - I would assume it would still call possess somewhere
I am on 5
maybe just try searching for Possess within that file?
Will do later, gotta run now. Thanks for the pointers π
π
any ideas why RotatetofaceBBentry breaks if i run my pawn around behind the ai?
it stalls on the task until i run back into success range
@ocean wren Oh hell, i thought there was one but i didn't see it. my bad, i'll go check that out, much appreciated!
What do you think is happening? Some days ago this haven't happened. It's just a simple Move To Actor sentence...but now.... the ai pawn is colliding with...something?? The mesh even....rotate?!! WTF I can't tell you what is happening , I'm so confuse haha. Thanks for any help π
I have cheked every collision setting of every actor...and nothing wierd...
UPD: in a new level, the bug is not happening...nice xD
UPD2: is happening again xD
does rotatetofacebbentry rotate the character at all? or does it not and it just claims success when you move in front of it
~~I'm working on a bt and for some reason I can't have a MoveTo node use any of the values on the child as keys. does anyone know why that is?~~The new ones are all "Object" class, I needed to use an actor
can someone explain these points to me?
Is there a way to detect path when he's Blocked?
good point, it's not actually rotating at all once I took out the moveTo
Rotate to Face BB Entry is implemented using the AIController's "Focus" system (similar to Set Default Focus). AIController uses the focus inputs to determine its Control Rotation. This rotation can be applied to your pawn either directly using the "Use Controller Rotation *" settings, or by the Character Movement Component if you have one (comes built-in to Character) using "Use Controller Desired Rotation"
just had to find the magic combination of checkboxes to get it working
uh huh π
But you really want to internalize how this all works
Because when you get into more advanced stuff, you will be toggling these checkboxes at runtime to achieve what you need
I only came back to ask my own question about these checkboxes
What is a good way to implement proper backwards walking using CMC / Navmesh / MoveTo
ie, lets say my focus is pinned on, for instance, an enemy, id like to have the AI navigate to a position without turning, by passing the appropriate control input (X/Y) in, so that my ABP can react appropriately (using the appropriate blend space walking states)
im suspecting the best path is to override AIController::MoveTo, but maybe someone has another idea
Well, I'm learning a lot about the focus system.
Three priorities of focus:
- "Default" Focus (priority 0): Bottom of the rung, only used if no other focus is available
- "Move" focus (priority 1): PathFindingComponent sets this during a move operation. Thus, "Default Focus" is always overridden by MoveTo.
- "Gameplay" focus (priority 2): This is what is set by AIController::SetFocalPoint. No built in BT service to control it, but one can be made.
If I recall, there's a checkbox on the moveto BT node to tell it to face the path or to face the focus actor? if there isn't I might have added it π
i think you added it π
Is it bad design to set the AI state from inside the behavior tree?
Let's say the AI does a short task in a state, and once done, I want to set it back to its last state. Is this fine to do through the BT or is there a better way?
There's no right or wrong way. It depends on how your AI works
NO STATE! π
only data
and priority
higher priority pre-empts lower
so if you're doing something low priority and a higher priority thing becomes available, then you switch to the high priority
once that high priority task is no longer available (through conditions) then you'll naturally go back to the lower
the point is to avoid thinking of it as states and transitions
its just "what is my highest priority right now based on the data"
and conditions enable/disable the priority order
so you might have a really low priority idle state that just.. noodles around, finds things to look at and looks at them etc.
A mid priority that goes to work
A high priority that avoids an oncoming train
the conditions of when a priority task is available is the key bit.. changes in the BB are how you know the priority can change
i.e. "I'm about to be hit by a train" might be a value in the BB, which is a condition on the "get off the train tracks" branch of the tree
@ocean wren Thanks for the explanation! Just a question, why would you not check these conditions in code and based on that, you set states which you can use in the BT, like if there's an oncoming train, set the state to avoid train. I know this goes against what you said but it keeps things much more organized and to the point in a BT, so I'm wondering why this is a bad choice?
@ocean wren did you do anything interesting with the dalle thing btw? a friend found some "dall-e mini" and I asked it to do William Shatner as Duke Nukem which is probably one of the best results I got out of it lol
The problem is that conceptually, trying to manage "state" invitably ends up with you thinking about how you go from one "state" to another and that was what we were moving to BT's for in the first place. Because state transitions are really hard to manage at any sort of decent scale.
You can improve things with HFSM and use heirarchy, but BT's try and avoid it by adopting a priority approach, which is actually more reasonable.. if someone shoots at you in real life, you're not bothered about previous states, you're bothered about getting your head down as priority
Its a different way of thinking and SHOULD be easier if you can make the mental shift
That said, people cling on to states pretty hard π ask everyone in here π
I've been playing with it for a good amount of time now and its truly revolutionary
Does take a bit to figure out how to direct it
But I've generated hundreds of images now
I've been playing with a discord based image generator called MidJourney as well, but Dall-E2 is better imho
The problem is, at some point, they're going to notice I'm melting their GPU's π
not that they don't have many thousands of course
but they're going to throttle me eventually.. then what am I going to do for casual artworks?
Weird, discord not likeee
Makes me grumpy
That was an image I generated for chat this morning when my heating was off π
should probably have joined the waitlist the first time I heard of this and not after you talked about it
prolly have a hundred thousand people waiting for it by now lol
I dunno, its weird.. I suspect they randomly select, because I didn't sign up for the new one until about a month ago
mind you, thinking about it, I probably signed up for the previous version a few years back π
Figuring out prompts for this stuff is pretty weird, an artform in itself really
Yeah
I noticed dall-e mini struggled to put certain things together, but if I prefixed it with "imaginary" that somehow made it then do what I wanted
it's definitely a lot more crude and limited than what the proper one produces
The thing is, you're trying to figure out the latent spaces of a N dimensional vector, where the vectors are in different image and text spaces.. I guess thats always going to be weird until we figure out methods to isolate features (GAN's do a bit of that)
What was the prompt you used again?
I forget what it was, we were just goofing around by making William Shatner and Steven Seagal do weird things lol
one thing I've been doing, is saving the generated images alongside the prompt texts.. so I've got a history of generations for a gallery I'll be doing
Yeah that's a good idea
Just right click and "save as" the webpage as a complete thing.. it'll save the images and the prompt text as a directory
I've been eyeing up a printer to maybe print some of my favourite generated images as art prints for a gallery
Havent been into work to check out the large format printers yet though
hello, the bug is caused by the dynamic runtime of the recast nav mesh....I continue not understand anything xd (I'm using UE5)
It's a bit hard to say but does the actor that's moving also modify the navmesh?
if it has can affect navigation enabled then it will behave erratically
thanks! it works
the mesh wierd rotation continues....but for the moment I don't care about it hehe
One for you Zomg:
William shatner as duke nukem
Sorry, william shatner as duke nukem, digital art
Probably not enough images captioned with duke nukem as a term
But look at the quality of the faces, these are definitely art quality, its pretty insane
These diffusion models are pretty crazy
I'm waiting for access to googles new one too.. Imagen?
does more photorealistic stuff
Personally, I like the Dall-E one, its got my style of art down
Yeah the quality is really impressive
I expected it to be the quality of what I posted from dall-e mini because that's been the level of quality these are
even dall-e mini can do some interesting styles, for example I asked it to do a few "in style of the simpsons", "as a salvador dali painting" and "in style of H.R. Giger"
Thats the difference with the large models, just the vastness of the model gives it more power
the quality is much worse but it gets the basic qualities of those styles in there pretty well
oh yeah, "in style of minecraft" also produced a reasonably convincing "minecraft fan art" type image lol
Yeah, the Clip embeddings are likely the same
its the diffusion decoder that's going to be different
There's a Dall-E 2 clone on github, some people have been reverse engineering it π
Dall-E2 was trained on a dataset called LAION, which you can get hold of.. I'm hoping we'll get an open source Dall-E2 soon. Which then I can run on my GPU π
Because I'm paranoid of losing access
I wonder how long it'll take to generate something on a single gpu lol
...and how much disk space does the whole thing take
Well, its just a ML model
it has to fit in a GPU
and I've got one with as much GPU mem as any other out there I believe
48gb on mine.. so it should run, maybe not as fast
But remember, these are actually 256x256 images upscaled twice with a diffusion model
so not THAT big
its the training that's the problem
But a pre-trained model is fine.. I reckon a 3090 might even fit one
interesting
If you get yourself on the MidJourney beta, they actually price some of this stuff up
and their model definitely runs on a single GPU per generation
They moved the upscaling to different set of GPU's
Hmm, it'd be interesting running a model on AWS or Azure thinking about it
Weird how this model doesn't like doing hands:
https://cdn.discordapp.com/attachments/408846404367155210/979020623445626890/unknown.png neither does the mini one lol
@ocean wren I got a request from my friend "Can you do Steven Seagal watering flowers in a pink dress"
lol
hahaha.. worth a try
Anyone know the name of the bad guys from that Vin Diesel film
goddam can't remember their name
"You keep what you kill" guys
He's been in quite many
oh that's chronicles of riddick I think?
not sure who said it tho
yeah, what was the name of the bad guys?
I htink Karl Urban was in it at least
The top middle one is kind of interesting proportions wise
My friend described the result as "Disney Jason Momoa character" lol
I don't think I could get away with that as a prompt sadly π
its very censored unfortunately.. lots of taboo keywords
When debugging EQS, I cannot see the scores using UE5, I had no issues with this in UE4.26 - does anyone know how to show scores?
Hi, what's difference between Pathing Grid and Grid ?
How to handle Senses config other then Sight / Hearing / Damage?
I know you have to write your own C++ ReportOtherSenseEvent.
But how do I listen to those events and react to them?
The AIPerceptionComponent OnPerceptionUpdated events doesn't get triggered by those other Senses.
You need to write a custom sense class for it
So I can't use the normal AI Team or Touch Config Sense class? I need to inherit from them?
If you want to report custom sense events, you need to create a custom sense, yes
you can inherit from one of the existing ones, or from FAISense or whatever the base class for them was
I don't want custom senses. Just use the other ones besides Sight / Hearing / Damage which didn't got the same treatment in support.
How can I react to FAITeamStimulusEvent for example? I wished it would automatically trigger the AIPerceptionComponent OnPerceptionUpdated event, but it doesn't when I use my own Report Event function:
void UCustomBlueprintFunctionLibrary::ReportTeamEvent(AActor* Broadcaster, AActor* Enemy, const FVector& LastKnowLocation,
float EventRange, float PassedInfoAge, float InStrength)
{
if (Broadcaster)
{
if (UAIPerceptionSystem* PerceptionSystem = UAIPerceptionSystem::GetCurrent(Broadcaster))
{
FAITeamStimulusEvent Event = FAITeamStimulusEvent(Broadcaster, Enemy, LastKnowLocation,
EventRange, PassedInfoAge, InStrength);
PerceptionSystem->OnEvent(Event);
}
}
}
Ohh that's what you mean
Yeah the team sense is a bit of a mystery to me tbh
It doesn't seem like it does much anything, it's not documented, so it seems like it might be incomplete
Similar to the Touch Sense :/
I'd say your best bet would be to first try and figure out how to correctly trigger the sense first of all, so that it actually receives the event
I have a look on how the AI Damage Sense manages it and compare
I'm trying to understand node instances and node memory in C++ BTTasks. Any help appreciated.
From what I understand, by default nodes are not instanced, so if you want to save data and use it again, you will need to utilize uint8* NodeMemory. But what if you set bCreateNodeInstance to true, does that mean the node is now instanced and you can store data on it? What is the downside to this?
Basically, how should I know when I should use an instanced node vs when I should use NodeMemory?
afaik there is a small performance impact from it
instanced nodes can store any kind of data and delegates and whatever on them just like anything else
non-instanced nodes have some limits but I've not really fully figured it out - it seems some of the builtin nodes which aren't instanced bind delegates into themselves which seems to suggest they are actually still somewhat instanced (iirc)
but at least with non-instanced you're supposed to use the node memory function to store data instead of storing properties on the node itself
Ahh I see. Looking at the native tasks, they mostly only finish latent tasks in tick where NodeMemory is accessible. So I should probably stick to instanced nodes unless I'm planning on only using things like tick or other built in methods that pass in NodeMemory
Yeah I don't think the perf impact is really an issue for most uses, all BP based BT nodes are instanced afaik
It makes small difference in terms of performance if you are not going wild with high count of enemies or very absurd features. But it makes a huge difference in terms of accessing to features and things not exposed to BP
The team support in AI perception, and the sight target interface are useful things that are C++ only, not really sure what else π€
There's some bits for navigation system where you can look at more detail about the path, and delegates for rebuilding navmesh and such but those are maybe a bit more niche
im making a stealth game so my AI:
- Follows a set path untill it detects the player or dies or detects an environmental change (like a door opened or a body found etc).
Whatever you do, always create a prototype first in BP because you are also going to playtest it and modify it later on, on the long run
Then if profiler proves any overhead then move it to C++
i mean the max amount of enemies il have even in a huge space is not gunna be above 20 currently as im just working on a larger prototype/ Demo
In normal gameplay programming you might prefer to do most of the things in C++ first but in AI my personal preference is always going wild with BP then moving to C++ unless its some sort of math or any heavy calculation/lookup operation
Just go with BP first, your scale is perfectly fine to develop everything in BP
Use C++ to get 100% benefit of EQS and creating custom systems for low-level things
There's probably one thing you'll want C++ for: doing more complex targeting for AI Perception: Sight. But that's something you can do much later.
im using c++ for like anything the player is doing A LOT like movment.
I do want to do bone targeting based detection in the future
Yep, that's only exposed to C++, AFAIK.
If you want to do it using ai perception yeah, needs IAISightTargetInterface
i want to make a waypoint path system for my AI and i want to be able to in editor and in BP change actions that the actor that goes to that waypoint can do (like play animation, sleep for a certain time, continue walking or Wait for a certain amount of time) can EQS do this? or is this VERY complicated and a c++ thing?
dependsβ’οΈ
its not complicated though
just can be preferred to do in C++ if its going to be extended
what ive described is pretty much what i want apart from environment changes
so like if a guard spots a dead guard or something and obviously the player
Once you start down the rabbit hole, you'll realize how deep it goes π
Howdy, i'm very interested in Smart objects due to how broadly useful "Ai does THING here based on criteria" is. It seems like you could do alot with them, from ambient anims to AI cover-system points, to door opening, ect.
Is there some major limit or hangup to the smart object system i should be aware of?
I know Smart Objects are used VERY broadly in many games, it's something i'd have needed to write on my own but since it's already here in the engine i figure i should just use that.
For Example, i'm planning a Star Wars:Republic Commando esk game where you order AI to take up bespoke Defensive Points, where they more-or-less turn into turrets until you tell them to leave. Only 1 unit can be at a point at a time, and most of what changes is they just enter a different state (new anim, don't move, change weapon).
That sounds like a solid use for the smart system. THe reservation means two units won't take up the same spot, and all the spot really needs is just some info for the squad member to read, no logic of it's own.
There's nothing stopping me from just writing a tool like that myself, it doesn't seem complicated, but again since the system is here i figure i should use it?
At least for a usecase like yours one thing that comes to mind is that it could end up being kind of static
Eg. if you order a squaddie to defend a location, they would just move up to the smart object and do their thing, so you'd end up having to define a lot of them for every single thing that can be done there, and for multiple positions too maybe
not saying it's not possible but there might be some design considerations for it
That's fair, if it was a more robust system with more options then yeah that would be trouble. At least in the thing i'm aping from, there are like 3 different kinds of Defensive Spot, and each spot tells the Squaddie to either Snipe, Throw Grenades, Use Turret, and such. You can tell at a distance which kind of spot it is, there's not much decision making that needs to go on AI wise.
I'm trying to keep stuff straightforward and simple, so going for the most static (Green cover is alwyas Snipe cover, in Sniper Cover AI always use Sniper Animation_1, and always uses AI_SNIPER_GUN) seems like a good way to do it. If it was gonna be a more dynamic system, then yeah needing to define so much so often would def be an issue, that's a good point.
So, as much as I am looking, there doesn't seem to exist a function that could be called from an aicontrller or a behavior tree that simply turns the character according to a given Rotator.
How would I go about implementing that myself? Still a bit unsure about how things are structured. Basically I'd write an analouge to Move To, so Rotate To I guess?
you just set rotation
iirc there is a value on the character movement comp which controls how fast it can rotate, combined with that I think you can use set focus or something to have it turn facing a certain point
or something along those lines
right
But I don't have such a point, I only have the rotation
I mean I guess I can construct one
yeah to manually smoothly rotate you can RInterp the rotation over time in tick
but that seems like an inefficient way
That response can you can add for both your last statements π
and the Event Receive Tick AI is the right place for that?
if you're doing it in a BT node that would probably work yeah
Other question: I used to move my AIController controlled pawn with AI Move To. Now I changed it a bit that the PlayerController references an AIController that owns the Character. However somehow this broke the AI MoveTo function. Broke as in, it just doesn't run at all. No completed, no failed, no movement.
just having a ref to the ai controller from the player controller shouldn't do anything like that
a ref as in a variable that contains it
Hi guys, is there a way to avoid casting a Task, I want to call my AIEnemycontroller from the Task that runs the Behavor tree, but I was told that Casting is not recommended and that there are other ways, but I do not know which ones. π¦
Anyone have experience with running AI functionality on client-side (i.e. NM_Client)? Entire AI system is not instantiated on the clients by default, but it seems I can enable it with Engine.AISystemBase.bInstantiateAISystemOnClient=True in Engine.ini.
Just wondering if there's any pitfalls/gotchas with turning this on. For example, to run target reticle rendering based on EQS query results, client-side-only.
Is there some kind of collision that AI can't hear through? Let's say that i want AI not to hear me making loud noises through a specific wall. How do i do that?
Is ai really the hardest math wise when coding?
I've heard it is
Let's say like in an fps as an example
@teal imp I don't think it's any more or less math focused than doing other gameplay coding, but alot of AI is build around complex movement, and movement requires knowing something about vector math.
the difficulty is more about knowing what kind of ai you need to build that's best for the game you're making. "good" ai doesn't really mean anything, it's a matter of if it can solve the problems you need it to solve.
Alright I think I get it
The trouble is there's 1000 ways to do it. If a bad guy needs to know where hte player is, there's alot of ways to Get that info, store that info, and share that info. it could be all on the unit, the ai could be talking to some scene observing mastermind, every action anybody makes could be preplanned, it's up to you! And it's not like there's one best answer, each answer is kinda bad and annoying and you just make the best of it.
Game Development: Everything is bad and annoying but you make the best of it.
Thanks
If you want maths, you probably want graphics or physics π
If i recall, EQS doesn't need the whole AI system to execute? It might be worth just trying an EQS query first for that.
how, if possible, to add custom blackboard property type without editing engine source? π€ I'd really like to have FGameplayTag blackboard key instead of using FName every time
Stuff it into a struct, the duct tape of unreal 
Err no. Sorry. A UObject. The other duct tape of unreal
right, I guess I just have to make one of those and register it in every way the other BB types are registered
maybe try multiline tracing/shape sweeping from an NPC to the instigator or its pawn owner and see if any hit result is with the collision of some specific type?
If that works without an engine mod then cool, TIL!
otherwise, no. It's been a while but I recall you can store UObject pointers in the default blackboard
i should have quoted the word "just". By briefly looking at all the references of one of default BB types I can tell that one would have to override/inherit several things and I'm not sure all of them are possible
EVERYTHING is possible
just.. more or less difficult
Hmmmm, so I've got a lil bit of funding to do some unreal engine stuff over summer.. mainly something to do with AI and virtual production, but I want to do something related to PCG too.
I really wish epic would get on with things on the metahumans and actually do some decent clothing sets
Ok, so maybe nows the time to dogfood some of the PCG stuff and actually make a UE5 game using it.. at least as an experimental game
See how far generative art can get me π
Goddam this Dall-E 2 thing is... way too fun π
How do (if they do) exposed UPROPERTY values stay unique on non instanced BT nodes? I want to have a TimeLimit decorator version with blackboard value time instead of direct value. I'm lazy so I'd like to just override the OnNodeActivation method and override the UPROPERTY() float TimeLimit in the child class and then call the parent method. But is it legal? I mean won't it override TImeLimit for every other running BT since the decorator isn't instanced?
There was some oddities with it in that they are partially kinda sorta still instanced iirc
So try giving it the uprop and see if it works
Guys please answer me, does anyone know any youtube channel or blog about AI Unreal engine Advanced.?
your best bet is to search on google or youtube for the specific problem you're having
What specifically do you class as "advanced"?
I wonder how DOOM switches the behaviors when a specific event happens since they are using HFSM. Does the H (hierarchical) part helps in this case? For example AI is in a very deep state where it can not jump to a higher node but you damage it, it becomes something different and starts using completely another behavior. I thought they are switching the FSM asset directly but it also feels a little bit silly π€
If they wouldnt say they are using pure state machines, I'd say they are using something similar to state tree since it can switch nodes easily on a higher level
Well, yeah, a HFSM isn't anything particularly fancy. You just have to get your act together and figure out what transitions are allowed.
I actually kind of like statecharts which are just a matrix layout version of statemachines, where its a bit easier to figure out transitions
But the hierarchy definitely helps seperate out the major states. But doom creatures aren't massively complex anyway
What is the Grid Path AI controller for?
I am guessing moving the agent along a grid path?
Think they had them in Fortnite back when it was a tower defence thingy
Or maybe in paragon
hey all.. anyone know of some way one could increase the cost of traversing a path that requires having the pathing agent rotate to take it? preferably without extending the entire Recast system
What do you mean rotate to take it?
You can definitely mess with the path cost for entry and exit of a navpoly
the actual AI has to rotate to face a path to take it, I'm trying to figure out if there's some way of extending the Filter to increase the cost for nodes that would require the AI to turn 90 or 180 degrees to take
nodes?
polys, links, areas, whatever we want to call them/nav through
basically, if AI is standing at point A, and there's 3 links to point B below, in different directions, I want it to choose the one that requires the least amount of rotation to turn through.
I don't know of any built-in way to do this. Especially considering that the final turn angles aren't decided until after string pulling.
hmm, I guess you could calculate the angles after string pulling, but thats after its already generated the path
right now, it will always choose the exit from point A that has the shortest path to point B, but I want it to consider that turning around 90 or 180 should increase the cost
No, you'd have to do some custom stuff for that.. I can't really visualize what it is you're wanting.. but its definitely not something I've seen in the code.. wouldn't be a huge issue, but it'd be custom C++ stuff
oh, for sure, custom isn't the issue, i just don't want to override the entire Recast system just to add a few points to a cost π
The pathing system doesn't have the notion of facing direction.. so there's no support for that
If the specific angle doesn't matter, but rather the overall straightness of the path, there must be a way to modify the cost function to account for it.
Oh you wouldn't have to override recast for this.. just a few functions for the FindPath<whateveritscalled>
You're basically walking the navpoly's, not really that difficult
If you find the string pulling code, then work your way up from there to the FindPath code.. you should be able to understand the whole of what you need
What are you suggesting overriding here zoombapup? I was hoping to find something that would make sense in FNavigationQueryFilter, but i'm not..
I think its called FindPathAsync or some such? been a while.. but there's a function I think in the CMC that calls the find... which kicks off the normal pathfinder
the final path is returned after string pulling, so right around the handoff to the string pulling is after the initial path is created.. so look at the code that does the string pulling.. it'll basically give you a clue for the structure of that
I just did some paths and single stepped the whole way through, until I understood it.. then bodged in what I needed
understanding navpoly's and how it calculates costs for entry/exit.. But yeah, it doesn't afaik have any notion of directionality, so you'd have to write a custom FindPathWithFacing or something
And in reality you'd have to do a non A* through the navpoly's because the whole point of that is shortest path
well, what i'm thinking, is - if i could find where filter actually filters anything - when the query is made, cost a poly that is 180 behind me as 10x, and a poly that is 90 to my left/right as 5x .. and then that should make it Just Work
If I were doing this in not-unreal I'd just modify the cost function. Normally A* uses manhattan distance or something similar, but you could use a weighted manhattan distance + dot product or something.
instinct is telling me that wouldn't work.. but I cant explain why π
worth a try π
Your instincts are going to better than mine π I wonder if you'd get some non-intuitive results that way.
Yeah, feels like the case.. but I'd have to see it in action.. edge cases tend to popup in this sort of thing
it's a pretty limited system -- the idea is that you've got a path that you can get into from 4 directions, but you want to exit it going in the same direction you started. There's a set of links for each entrance and exit
so its not a navmesh?
it's a navmesh, but there's link proxies between parts of it
so are you following the navmesh or the proxies? π
and if you enter the entrance link from the 'north' facing 'south', i want the AI to use the 'south' exit link rather than the 'east'
So you want to increase the cost of backtracking?
So its really only the local navpoly's you care about then? not the whole path?
ultimately, yes.
I wonder how do you change a major state, is it something decoupled from the state machines like statetree or just literally a node in the graph?
I figured if NavQueryFilter could be used as an actual filter, i could just check the distance and direction of a given poly, and if it's close and in the wrong direction, return a much higher cost
alternatively, it seems there's something involved in a Detour system, but documentation and internet experiences with it seem to be zero
Its basically a state like any other, but each state can have child states, when you transition you basically just exit all children then exit yourself and then you go to the next state. Generally I've used a stack to control pushing and popping of states
There's a bunch of formulations, but usually there's just a "StateState(stateid)" kind of thing
oh. i wonder if i could override the Area to do it
As I said, I like statecharts.. which is basically a matrix of states
Haven't seen heirarchical statechats now I think about it.. that'd be interesting
Ah, I see. Child state node thingy
Yeah, so setting a state, you'd check if its one of your children, if not you'd exit and it'd pass back up to the root
I'm trying to find a reference to statecharts, and all I'm finding are UML statecharts, and various XML descriptors for state machines. Nothing that looks like a matrix to me? Am I on the right track?
It was a presentation at GDC I was at that discussed them.. might have a different name in other industries?
The main takeaway was that it was easier to design because you had all of the states mapped in the matrix and could tell which state transitions to which other state easily
We use it in graph neural networks a bit too..
Right, that sounds pretty powerful. I assume it's a 2d sparse array with states as the X+Y coords and filled cells with one or more transitions?
Yeah, exactly
So you could tell if you forgot a state transition because the grid cell was empty
And could do stuff like making sure a state had something transitioning to it etc..
And of course it looked easier for designers, its basically a spreadsheet
Right, and it would be pretty easy to build a typical visualizataion of that from the matrix (or vv) so you could take in the info in both ways.
Probably doesn't work that great for really complex HFSM, but seemed like a really nice usability design tool
Poor guy who explained it to the audience was shaking like a leaf though π
We were doing some presentations at the AI Summit, so my, this guy (can't remember his name) and another dude
me even
He had this bit of paper in his hand.. had to discreetly steal it from him, he was so nervous that it looked like he was waving a flag he was shaking so much π
I guess having like 500 people watching you got to him
Ah, I've found the key to googling this. State Table.
No Doubt. I've presented to audiences that size and the terror is real.
Seems pretty popular in Electrical engineering.
Ah yeah, that looks right
Yeah, state machines are used in process control logic stuff a lot.. probably from there
Weirdly, I find that Behaviour Tree's are actually easier to understand if they're laid out as a tree view rather than UE's top down left right tree
Bit like Damian Isla's original halo version.. I just prefer it, I guess because the text of each node is more condensed as its horizontal
StateTree system should be good in that regard
Yeah, that is a lot easier to read.
Its super easy to write tools for too, because most UI toolkits have listviews
i.e. heirarchical view widgets.. I mean why they didn't go with that is beyond me π
Once you have something as powerful as EdGraph, why not use it? My current toy project is building a Graph editor for HTN's, so I can see the appeal.
Yeah, EdGraph is pretty fun
I'm using it for a few plugins, mainly ML stuff
It irks me that they don't have support for rounded rectangles.. I'd really love to properly edit the damn UI code π
Howdy, question about Smart Objects. I went through the tutorial, but when i run it my character will find and activate smart objects, but will Use them without having to actually approach them. So they just play an animation in place, swapping between smart objects.
I've scoured the guide and as far as i can tell nothing's dif (though someting obviously is). When you're dealing with smart object, what in the process actually controls how close you need to be to activate it? It is on the object itself? Something in the Use detection? Is there some obscure Must Approach toggle somewhere?
Its on the object in the docs
Haven't done it myself, but that was something I saw in an example
Yeah, that's what i figured. I guess i just find it weird that nowhere in the demo does it specify pathfiding, or moving towards the object, or how they're meant to navigate towards it. (i mean yeah it says put a navmesh down but i think the Use BP just wraps navigation into it??) I guess that's stuff that's hidden in the C++ code for the objects? Seems like a weird thing to not expose?
Yeah, haven't looked.. usually for smartobjects you'd give it a starting location/rotation and then just expect the animation system to take care of the rest
In "Approaching the Smart Object" the docs seem to indicate that the agent is responsible for nagivating to GetSlotLocation.
At which point you call UseSlot.
But honestly, if you're trying this stuff, you're way ahead of me.
Makes sense.. so you can animate your character relative to some fixed offset and then just make sure your world objects have the same offset for the entry point and you're good
Yeah, that's what i'm gathering, that there's something weird about Use that doesn't really expose the kind of info i think it should. Like my dude is Using them, it's activating, it's just not approaching.
i guess i'll scour the city example again, but that also uses stategraph and other tools so it's obscured.
Well, you'd approach it first, then use it
Normally you'd reserve it first.. then move to the use point.. then use it
I would presume so, yes.
But that step doesn't seem to come up in the quick start guide
Which is what's weirding me.
I suspect that's because in the city samples their using zonegraphs
So the navigation isn't the same as a "normal" BT etc.
the quick start page shows the final btree, and a gif of it workin' is the thing.
Maybe BTT_UseSmartObject navigates too? But that would depend on you having the type of navigation it expects set up and working
Oh, I see, they have you build it.
The QuickStart and the Overview definitely disagree. One of them must be wrong.
Probably both π
Haha.
When creating a task for a Behaviour Tree, is it possible to specify what kind of object a key is? Or do I need to do a cast every single time the task is called?
The object in the Blackboard does have a base class set.
@tardy wolf I might not be getting the question, but could you just get the key, then make a var out of it, and then use that moving forward?
I currently have the keys being passed in as variables and using the Get Blackboard Value as Object nodes.
I don't have any Value as Subclass nodes.
Unless I'm misunderstanding your suggestion?
Tbh I'm not even sure if the cast is that expensive... but I do know that I'm going to be calling this particular task quite a lot so I don't want to find out at a later date that its killing performance.
The Quick Start seems to work without manual navigation.
You have to have a navmesh, but otherwise the 'Use Claimed Smart Object" node seems to magically know what to do.
Yeah, it composes an AIMoveTo gameplay task with the smart object trigger behaviour call.
You can specify the kind of object a key is, but that doesn't prevent you from having to cast it when you get it out of the Blackboard.
Okay so I take it I will always have to cast if its not one of the above value types?
Yep. If it's really performance critical you might need to find a sneaky c++ way to providing access to the object without casting. Or provide needed data without using a UObject.
@opal crest I'll look over my stuff again, maybe something's borked with my char's navigation? god knows. but i'll take another look later, much appreciated.
wow. this path filtering code is the absolute most brutal thing i've seen in a long time
Which in particular?
well, i'm figuring that there has to be some way of supplying a filter implementation, without also overriding everything else. Trying to trace it out, unless i'm missing something blatantly obvious, is just not hitting anything though
the default filter system clearly functions, but ... how?
I think I've found where I want to connect -- FPImplRecastNavMesh::FindPath eventually comes out with a dtQueryFilter... so, what I think I need to do is subclass dtQueryFilter ... somehow point UNavigationQueryFilter to use the new one... and then figure out a way to connect the Owner of the query.... dammit.
like.. the whole path following thing is based on costs, and there doesn't seem to be an actual way of changing the cost on a per-nav poly basis at runtime.
hmm isnt that what navmodifiers are for
as far as i'm aware that's static
thats true if you dont use dynamic navmesh generation
actually im not sure thats true even with static navmesh generation
no yeah you definitely should be able to add/remove/modify nav modifier volumes at runtime
well
actually im not sure you can move them
but you can modify their cost affect
If you need them to be added/removed/moved at runtime, then I think only dynamic navmesh generation would work for that
at least, with Recast
ahh, the original message
hmm. I think if I can figure out how to extend FRecastQueryFilter i think i can get there
looks like you would subclass AAIController, implement GetDefaultNavigationFilterClass
have it return your new UNavigationQueryFilter subclass
you can just set a DefaultNavigationFilterClass to handle that part of it.. it's figuring out how to alter code that actually affects it -- the calculations appear to only be done the first time a filter is used
what even is a class that begins with F .. i thought only ustructs were to begin with F.. but apparently also classes that don't have UCLASS ? hmmm..
yeah i think its just "not a UCLASS" but i dunno Β―_(γ)_/Β―
i mean its not like the recast codebase follows unreal conventions very well
"dtNavMeshQuery" (well thats detour, but yeah), methods like "updateLinkFilter"
right, i see why they're doing a bunch of passing things between layers.. but IMO major oversight not including an actual API that just serves as an actual implementable nav filter, without having to go through.. ::waves hands:: whatever this is
in case you havent seen this post: https://forums.unrealengine.com/t/overriding-a-cost-and-heuristicscale-frecastqueryfilter-dtquearyfilter-with-minimal-engine-code-changes/389131
Hi there, A question to anyone into tuning A* using the existing QueryFilter classes: Q: Did anyone try overriding βdtQueryFilterβ or similar A* cost/heuristic implementation changes without touching Engine level code like described below? Details: I recently tuned existing A related methods* by implementing my own set of UNavigationQueryFil...
layering violations
if the "dt" is "detour" in dtQueryFilter
i feel your pain this code is... something else
the post may be outdated, or they missed:
virtual void InitializeFilter(const ANavigationData& NavData, const UObject* Querier, FNavigationQueryFilter& Filter) const;
no actually that couldn't work either with just a reference
@atomic coral how did you get your filter in there to start with?
set it in AIController as the DefaultNavigationFilterClass for this specific AI
the current one is just a blueprint that has some numbers filled in
i meant FNavigationQueryFilter but i guess thats the goal
Right now I'm trying to do what RecastFilter_UseDefaultArea does ...
ok i think im starting to grok this stuff a bit more
huh. no idea if what i've got is going to actually work, but it compiles, which is a pretty huge step
so youve got it all wired in down to providing a filter implementation (INavigationQueryFilterInterface) in InitializeFilter() for your filter, probably extending from FRecastQueryFilter (which inherits dtQueryFilter and implements INavigationQueryFilterInterface), and then implementing getVirtualCost()
But then getVirtualCost() only gets called once?
that i'm not sure of. I've just successfully built something that compiles for the first time doing all that
as best i can tell that shouldnt be the case, and the docs indicate it should be fast like sanic or else problems: https://docs.unrealengine.com/5.0/en-US/API/Runtime/Navmesh/Detour/dtQueryFilter/
previously i was tracing down what was happening inside UNavigationQueryFilter to see if I could hijack that somewhere
i think you are on the right track doing what UseDefaultArea does-- getVirtualCost() is probably what you need to override
so then its the question of getting your querier down here
i should be able to cache that from InitializeFilter
what a mess, and no wonder no one has posted about going that way without also just overriding the rest of it too
that poster clearly missed this implementation redirection system
i doubt its new
i was missing it too
this is the post that got me a little closer https://forums.unrealengine.com/t/modify-pathfinding-cost-detournavmeshquery-subclass/342472/2
First issue, DetourNavMeshQuery isnβt a class, itβs just the header file that contains many classes for Detour queries. I assume though, that the class you want to subclass is dtQueryFilter - which handles path costs for Detour. The reason why it doesnβt show up in the editor, is that none of the Recast/Detour library classes are UObject classes...
which seems to indicate that you have to go through overriding the agent and much of the rest of it
but i'm pretty sure that this way will work...
i overrode and put breakpoints on passVirtualFilter and getVirtualCost just like RecastQueryFilter.h says to do, but no breaks. argh.
lol
Solution #3 shows you how to subclass dtQueryFilter, but itβs probably not your best solution - unless youβre invested into implementing your own Recast/Detour solution for UE4.
that makes no sense
Unfortuantely, you would then have to throw out ARecastNavmesh, and start implementing your own subclass of ANavigationData in the same fashion that ARecastNavmesh does - hence why this is the hardest option.
this doesn't appear to be correct at all
they probably missed the Initialize route with the implementation misdirection too I guess
why would you have to throw out detour to reimplement detours query filter
the docs themselves say this is possible, but they just don't spell out how to go from unavigationqueryfilter to frecastqueryfilter
hmmmmm
ok so, i shouldn't need to do anything with FNavigationQueryFilter, other than just fill it in right
not sure how passVirtualFilter fits in--- if you break in FindPath, are you seeing your instance?
the recast navmesh impl one no?
yeah i found it, over in PimplRecastNavMesh... not sure how to tell if it's mine or the original...
that guy should be an instance of your class
or
well
FilterImplementation too
since
That's a weird method there isnt it
huh, why do they do that
There's no interface magic there, no other implementations, its not virtual
would it not be valid to (dtQueryFilter*)FilterImplementation for some reason?
i think this is just some convention / "prepared for the future" thing
yes i'm sure preparing for the things marked "// @TODONAV"
its fine, they had whatever came first, then detour, then recast detour, then detour crowds, and now mass crowds
why fix all the bugs
or missing functionality
when you can just scrap and rewrite leaving the flaming garbage pile you left behind
some months ago i was digging around for some feature that i knew was in the code a long time ago, and found the section commented out with "// TODO: reimplement" or some such
ok, so, AI controller has the right filter set as default... OH i wonder if i'm overriding it in the MoveTo..
right, fighting the attempts of the past
im really sorry for the harsh words, to any Epic (or licensee) dev who had a hand in writing this code, as we lambast the work you did during crunch π¦
if there was just a simple public interface that was given the poly info and returned a cost modifier, this could be as complex as anyone could possibly ever make it, and it wouldn't matter to me
where would you defer the responsibility? im thinking a querier interface or something
querier->controller?
(im not sure if the querier is the controller or the actor here)
passing it up to the UNavigationQueryFilter would be really great
im not sure that works
the inputs to getVirtualCost are the polys, but the navigation abstractions should support navigation systems that are not polygon based
i think operating at this level does require you to be working within the particular details that detour as a navigationsystem implementation requires
to abstract it up to UNavigationQueryFilter feels like it would expose that implementation detail and eliminate a lot of potential implementations of the abstraction
not that it seriously matters
because im not sure its totally possible to skip it all (detour) anyway
but i think thats the idea of it
honestly given how.... special.... detour and the builtin navigation system is, i bet there are a fair number of licensees totally replacing this system for their games
that's why i figure adding an inversion of control as an escape hatch out of the layered implementation for ease of implementation may make sense: basically make this part of detour pluggable without having to subclass the innards
but on the other hand -- the docs are pretty insistent that overhead here is highly undesirable, presumably because it gets called every frame on the game thread
i wonder if it worked
i'm still trying to figure out how to tell what's happening
still not seeing your instance in the debugger?
I think the object value should show it's class
it's definitely not just a dtQueryFilter
as that gets subclassed even in the default implementation
at least if my understanding is correct
regardless, your getVirtualCost should be firing, even if you just check() in there
i'm getting an occasional fire of an ensure in AIController::MoveTo that doesn't make sense
which one
yeah this has been happening for a little while but i'm the only person who's noticed it for some reason
that ensure feels wrong
yeahhhhh
assert that: either the move request specifies its own navigation filter, or there is no default filter ?
that cant be right
no default filter should equal the ini default, i think
damn
I think the intent is: If you specify DefaultNavigationFilterClass then you cant use MoveTo() ?
but why
that sounds awful
oh, rather, you cant use the move request system
because MoveToLocation() is fine, it actually uses DefaultNavigationFilterClass
still awful
Nonetheless, you can still bypass that
might be worth it if the ensures are telling you this isnt a good idea
just subclass AAIController and implement GetDefaultNavigationFilterClass ? (#gameplay-ai message)
after all, i doubt every single actor in your game should be bound by this rule
it would be better to gate it at the controller so that you can still use the default behavior when this special behavior is not required
well funny thing it eventually sets it all to DefaultNavigationFilterClass if it's not set coming in anyway
but
the move request will have one defined
because it just gets it from aaicontroller
or do you mean: that itself gets ignored later?
my brain is melting switching between Ryder and Visual Studio lol .. Ryder is easier to research things, but doesn't work for me for anything else
i also hate Ryder's text editor
i use rider myself
im not a huge fan of jetbrains but the unreal specific nature, and the very good large codebase symbol caching and general ease of use after the learning curve---
that's how much i use it, i thought it was spelled with a Y
nonetheless --- the key here is that DefaultNavigationFilterClass is a feature of the default AIController class
if you subclass and customize, then DefaultNavigationFilterClass is not a thing
i dont know if it matters, but it might be wise to heed the ensures(), until you are sure that the ensure() is the bug
yeah.. i think i needed to add it to my behavior tree task that calls moveto .. it was not filling in the filter if none was given, thinking the lower code would fill it in
you dont need to fill in the filter, it is done by AIController
erm
ok not getting the ensure now
i'm hitting the constructor for my UNavigationQueryFilter several times at startup, but not hitting anything else
ok, how should I construct my FRecastQueryFilter? I'm just declaring one in a namespace, like the original does, but .. i'm not hitting anything in it
Ohhh--
UNavFilter_AIControllerDefault subclasses UNavigationQueryFilter, and when it implements GetSimpleFilterForAgent() it returns the AIController::GetDefaultNavigationFilterClass(). This is what they mean by the querier-specific filter.
one thing i don't see is hitting the constructor in my U filter after i hit play
are you actually using that AIController for the agent?
it better be, when i changed it he pathed differently
oh what filters are you defining on the actors
because you just need the default UNavFilter_AIControllerDefault to do it
but i wonder if you've changed those
defining where?
oh i just got a breakpoint hit at startup in my RecastQueryFilter.. i don't think that happened last time. interesting.
ugh i thought DefaultNavigationFilterClass was a global-- but you were already doing all of this π
its all property-scoped
ok it's hitting my InitializeFilter on first path
CreateCopy() is creating an instance of my FRecastQueryFilter, apparently
that sounds* right
or at least a copy constructor
if you haven't defined one and it's no-args then yeah
black blob means "most anticipated AAA hit :-D
it's probably not hard to look me up and find out what i work on lol
blade things I'm sure
anyway that should be good yeah
that thing is the dtQueryFilter
i wonder if twiddling with bIsMetaFilter or bInstantiateForQuerier would do anything
ohhh
i swear i can code, but the layers here.. crazy
if you are not getting valid querier in InitializeFilter or InitializeFilter is only running once, then that would make sense
i think.... somehow.... that default AIController implementation of the NavFilter is always there
even though it seems like you would override with DefaultNavigationFilterClass to replace that i wonder if its not the case
bInstantiateForQuerier is protected
no change with those
If you want to debug it, stick a breakpoint in the constructor, note the address of the this pointer.. then when you come to use the filter, check the address of it in memory
Good reading you two figuring this out by the way π
@mint terrace ... so.. shouldn't it be hitting the constructor in my FRecastQueryFilter when it goes through CreateCopy() which does a new(*this) ?
The reason the recast code looks so weird, is that Mikko, the guy who wrote it, is from the demoscene and one of the things you do there, is just allocate a block of memory and read/write stuff from that.. it kind of forces a different code mentality. That and usually these guys are not CS trained.
SetFilterImplementation does
QueryFilterImpl = MakeShareable(InQueryFilterImpl->CreateCopy());
CreateCopy does return new FRecastQueryFilter(*this);
at that point, I'd expect the breakpoint in my FRecastQueryFilter to hit
or.. that's just creating a new pointer isn't it, not a new filter
... or...
stick a breakpoint in your constructor and look at the call stack? or stick a breakpoint in that CreateCopy func and see what it returns?
the FRecastQueryFilter is only being hit at editor startup
So does that CreateCopy ever get called?
yeah, it's returning a void pointer to 0x000001f4a62de200 ..
But that doesn't call the FRecastQueryFilter constructor?
it does not
Not even the base class?
good question
ok at InitializeFilter, Filter.QueryFilterImpl is now also a ptr to that same address
i can't breakpoint FRecastQueryFilter constructor
there is no implementation for a constructor there
ope, there it is.. over in PImplRecastNavMesh ..
@ocean wren yeah base class constructor isn't hit at game startup or at path find either
So heres a question.. your passing your query filter in FPathFindingQuery?
Maybe stick a breakpoint on that SetFilterImplementation? see where its called
Hmm, seems only two places can call it
Well, three if you count the constructor
Seems like ANavigationData returns the filter implementation
NavFilter->SetFilterImplementation(NavData.GetDefaultQueryFilterImpl());
Guess it makes sense, means that Recast version of ANavigationData returns a recast filter, I assume that the grid based pathing returns a grid based filter
just finished eating
Welcome back
that's insightful @ocean wren
ok, so, the SetFilterImplementation is giving me a pointer to -- presumably? -- my filter, and FindPath is getting that same pointer as FilterImplementation
the QueryFilter is... 8 bytes higher
wait it's not doing some trickery to skip the constructor is it?
the constructor in my FRecastQueryFilter is only hit at editor startup
sounds like uclass cdo?
it's not a uclass at all ..
ohh ok no
Where does the call stack on your constructor say its being created?
it's the level of indirection
that first one is supposed to create the second one that's querier specific, yeah?
it's at editor startup because that's engine start
yea it's being called in EnginePreInit ... down to LoadStartupModules
It seems to me, that the Query filter has the filter implementation provided to it by the navigation data
oh wait, getting triggered by the AAIController subclass CDO
So the question would be, is there a function to set the impl on the navigation data class
am i constructing this thing correctly, by just creating one in a namespace, and then referring to it?
the filter implementation (can) be set in InitializeFilter()
thats what URecastFilter_UseDefaultArea does, with Filter.SetFilterImplementation()
Hmm, so UNavigationQueryFilter is a UObject
let's try overriding CreateCopy in my recastqueryfilter and see if that hits
It looks to me, that the QueryFilter is taken from FAIMoveRequest
virtual GetSimpleFilterForAgent(Object &Querier) is probably getting called on your instance
have you overridden that
i have not
thats what zoombapup means by the navdata taking over
you want the red path, but the navdata providing is the non-red path:
the issue is here, there is no way to memoize the querier?
if you return yourself as this TSubclassOf, it would make a new one per agent (read: actor mostly)
thats implementing GetSimpleFilterForAgent which is virtual
hey! my CreateCopy is the one being called
if it is not true that (*SimpleFilterClass), then control falls through to the navdata's choice
and the default impl is
Ok, here's how I would do it: If you look at AAIController
PreparePathfinding
Query = FPathFindingQuery(this, *NavData, GetNavAgentLocation(), GoalLocation, UNavigationQueryFilter::GetQueryFilter(*NavData, MoveRequest.GetNavigationFilter()));
ok, so, if that's correct, then we need bIsMetaFilter = true
Pass your own query filter there
I suppose
this almost makes me want to go back to operating systems development π
is it accessible?
sure, i'm overriding that class
oh yeah that's nice
ok, GetSimpleFilterForAgent(*Querier) returns null the first time through
and again the second time thru
I meant is it protected as opposed to private but im sure it is
instantiate and metafilter are both protected
huh? you would need to return your class there. But I wonder if this two level indirection would be skipped just setting the filter on the query like zoombapup said
PreparePathfinding goes to BuildPathfindingQuery .. let's see what's in there
the idea is you would override that and do SetNavigationFilter
instead of using the default class field
it doesn't solve retaining access to the actor/controller though
because SetNavigationFilter is still a class
and im not sure that it still wouldnt end up in the GetSimpleFilterForAgent() path
at which point, youd either have to take it for that querier, or you get the navdata's default which isn't your class
ohh wait no you can get the querier its going to the CDO
Maybe this isn't actually going to work --- A "meta filter" selects a different filter class given the properties of the incoming agent (querier)
No matter what you do, ultimately it will resolve to a "simple filter"
ok in GetQueryFilter ... SharedFilter = nullptr regardless of which side of the ternary it takes
FSharedConstNavQueryFilter SharedFilter = bInstantiateForQuerier ? nullptr : NavData.GetQueryFilter(GetClass());
ooh, gotta wait til the second time thru to get a value there
Yeah but its going to go to the NavData and ignore everything you set up on the AAIController
efffff
and that implementation is not virtual
/** get cached query filter */
FSharedConstNavQueryFilter GetQueryFilter(TSubclassOf<UNavigationQueryFilter> FilterClass) const;
is it possible to politely ask epic games to add certain feature to SmartObjectsModule and where would be the best place to do that? github issue? answers.unrealengine.com/? π€
Join the mass channel and let the guys there know, they're talking to the Mass guys right now
and SmartObjects is kind of part of mass
Theyre talking to the Epic devs of mass that is
yes FMegaFunk Enterprises, LTD π
ok, so, if we want this to have a hope of getting the right thing, we need GetSimpleFilterForAgent(*Querier) to return something right
yeah... this might be the key. did we mention this already? if we did and i missed it or dismissed it, i apologize
i'm confused again. what is the main purpose of smart objects? Is it mainly mass with its ECS(?) approach for large cities or regular behavior trees/state trees as well for relatively small amount of NPCs?
i did mention it... i think?
overridden it and returned your own class
SmartObjects are a general AI thing, but they were written and implemented by the devs who created the Mass system. Presumably to flesh out the city stuff, so those would be the people to try and influence
with the meta filter flag enabled
why isn't the default implementation for that to return GetClass() or something useful lol
because if it did that, then it would not be able to bail to the NavData cache lookup
which btw, is actually still relevant
well, eh
hhh ok thanks. Unfortunately currently I'm way too far from doing anything with mass so most of those things kinda scare me π
Well, nobody really has a good handle on it yet, MegaFunk and the others in #mass are working it out and doing docs.. the Epic devs are helping them a bit and taking requests
absent proper docs and all, a community effort makes sense, but I wish epic would get its shit together and schedule documentation as part of development
or at least some more inside unreals
@mint terrace ... so... it only hits that path if bIsMetaFilter is true... but then it queries the Default Object, and only hits the useful part of that if it's bIsMetaFilter is false. What?
ohhh wow
do
do they need to be two classes
so you can have one metafilter + one regular one?
that does seem crazy
yes. i.. haven't used DefaultObject much since UE3, so I'm not real sure how that would work
thats just the object your constructor sees
in UE3, i'd just set the defaultprops to false, and then set it in BeginPlay lol
each UClass (class with UCLASS attached) has a CDO (Class Default Object), which is created when the UClass is loaded
but that doesnt matter -- you would need 1 class that has bIsMetaFilter=true with your GetSimpleFilterForAgent() implementation in it, and one more that is bIsMetaFilter=false that has your InitializeFilter() in it, where you set the filter implementation
that's terrible.
at this point im hoping it works because this is a crap load of boilerplate
hahahaha
i just commented that check out, let's see what happens
which check?
if (DefFilterOb->bIsMetaFilter == false)
ahh custom engine build i guess
....
you might not believe the results
now i know what that does lol
it is quite obvious now looking at it what it does.. lol
it infinite loops, calling itself
that... probably makes sense why you'd need two classes eh
or... was returning GetClass() from GetSimpleFilterForAgent not the correct play
well like you said
it's checking the meta filter param and then delegating a class reference lookup to that meta filter.
and it disallows recursive meta filters
if i'm not mistaken, this will just cause it to hit the not meta filter path, and return the bad thing anyway
I think you're right :-(
subclassing UNavigationQueryFilter must only be intended for meta filters
I think you guys are overthinking it.. surely PreparePathfinding and overriding the QueryFilter there is all you need to do?
NavFilter_AIControllerDefault .. how does that not run into this
if it ends up in the cached path then yes
The query that PreparePathfinding creates then gets passed to: FPathFindingResult PathResult = NavSys->FindPathSync(Query);
however, not clear how you could use that to maintain the querier reference, unless that gets attached to the instance for you
but that's not solved the other way either.
i don't even see what you're looking at zoomba
i may have spent entirely too long staring at this
Query = FPathFindingQuery(this, *NavData, GetNavAgentLocation(), GoalLocation, UNavigationQueryFilter::GetQueryFilter(*NavData, MoveRequest.GetNavigationFilter()));
When it prepares the pathfingind query, it constructs this Query object
Then in requestpathandmove it uses that query object:
FPathFindingResult PathResult = NavSys->FindPathSync(Query);
Inside the query object is the navigation filter
So something like:
Query = FPathFindingQuery(this, NavData, GetNavAgentLocation(), GoalLocation, MyNavFilter);
PreparePathfinding() is deprecated and unreferenced?
No its not
what class? AAIController?
are you using 4.27?
it's deprecated in 4.27 too
the above is a solution wide search for the name of the function
i think its dead
its now FindPathForMoveRequest
still virtual
i think calling super and then overriding the filter class would be the way?
Well, you need to look at where that Query parameter is.. its created somewhere in AAIController right?
Which version are you guys on?
5.0.2 here, i assume they are on 4.27
yea i'm 4.27
the query is passed in probably with a default
but its reference, no const
the intention is to set up the query like PreparePathfinding() did, I think
just with a different API
yeah its the same API as PreparePathfinding() was, but with an additional FNavPathSharedPtr& OutPath tacked on the end
ohhhh
Yeah, basically, pass a different filter to the Query object, because that's where it gets it from for the pathfinding
prepare the query, then pass that query into the super
void AMyAIController::FindPathForMoveRequest(const FAIMoveRequest& MoveRequest, FPathFindingQuery& Query, FNavPathSharedPtr& OutPath) const
{
Query.SetFilterClass(MyFilterClass);
AAIController::FindPathForMoveRequest(MoveRequest, Query, OutPath);
}
so, what we're finding, though, is that even setting up the filter, it still ends up going to the Default Filter. I'm not sure that this would change that
it might not
its your last best hope
if its not this, im sorry
its time to reimplement recast/detour* like that fellow said
well yeah
in fact that first post i linked, they did exactly that
just make GetQueryFilter() virtual on UNavigationQueryFilter
bam
do anything you want
i assume you for some reason really really dont want to do that
because its right there, you already edited out that check
yeah but editing that check out was not the answer to get there .. i'm still trying to figure out if there is a correct answer to get there or not
yep, try the path of setting the filter class on the move request
also holy crap
this code is ridiculous
trying to be too many things for too many people without the right layers of abstraction
I think @atomic coral is volunteering
:-P
but that's also never gonna happen
it is already too many things to too many people
nope, i suspect my boss is going to be unhappy that i haven't found a solution for this in 12 hours, let alone if i took the time to refactor navmesh
well the escape hatch is there
sounds like y'all aren't afraid of a custom engine build
nope not at all.. i'm just not sure what the escape hatch would be there either
ah.. yeah could be
then just implement it and return your own damned F thing instead of even necessarily needing InitializeFilter
maybe it's the only way, I dunno
yep, try the path of setting the filter class on the move request
sounds like maybe this isnt changing anything?
i'm still back a few ideas before that on setting up two different classes
your rebuttal to the idea was convincing
these will be the same
and they aint virtual
if they're the same, then you are right, how can it not recurse a second time, and then fall into the default simple filter implementation path
i'm not sure what to return from GetSimpleFilterForAgent .. i guess I could add a property to select it from the editor
GetSimpleFilterForAgent can only ever usefully return a data-only subclass of UNavigationQueryFilter, so that you can change things like these:
and then you can modify what subclass you use based on the state of the actor/controller when the navigation occurs
GetSimpleFilterForAgent can only ever [seemingly] usefully return
but why is this different?
wouldnt this InitializeFilter() forever be useless, even if you assigned URecastFilter_UseDefaultArea's UClass* to whatever filter class property?
probably because, in fact, the move request's implementation skips the indirection we've been grappling with
hmm i guess its actually Query.QueryFilter = myFSharedConstNavQueryFilter not SetQueryFilter()
wait oh crap its not a UNavigationQueryFilter at all
nope
@atomic coral well that will absolutely bypass all of that crap
hmm?
yea i think the two class thing is a no go, or if it is, there's something complex and misunderstood about it
implement FindPathForMoveRequest(), set Query.QueryFilter to (a value of) FMyNavigationQueryFilter, where that one's constructor sets QueryFilterImpl to an instance of FMyRecastQueryFilter
the FMyNavigationQueryFilter constructor could handle accepting the Querier but im not super sure what lifecycles we're talking about here
FindPathForMoveRequest should? already be receiving the UNavigationQueryFilter that has been pointing to the FRecastQueryFilter .. i'm pretty sure
you mean its pointing to FMyRecastQueryFilter ?
aka, your own FRecastQueryFilter sub.... erm struct?
yeah to mine .. i'm not entirely certain of that, because eff me if the debugger isn't telling me squat thru these layers
yeah but if your own filter class is running
then you should be receiving getVirtualCost() calls
thats literally the end of the road there
once thats in place, getVirtualCost() should be called
so, it selects my custom UNavigationQueryFilter, sets up a FAIMoveRequest with that set, then calls BuildPathfindingQuery on that
using InitializeFilter() there?
to get the FRecastQueryFilter subclass in place
if thats working, why arent you getting getVirtualCost()
that absolutely should be the case
i mean tell me you've tried UE_LOG in there
screw the debugger
debugger lies
especially ryder
getVirtualCost consists of a UE_LOG and a return dtQueryFilter::getVirtualCost(....)
and that is the dtQueryFilter that is observed in navmesh pimpl
same pointer? and when you step into getVirtualCost on that dtQueryFilter?
i'm... really not sure
ok, so, we have a UNavigationQueryFilter that is bInstantiateForQuerier = false, bIsMetaFilter false, implements InitializeFilter to call Filter.SetFilterImplementation(&EMyRecastQueryFilter::FilterPreferredFacing), which is defined as namespace EMyRecastQueryFilter { FMyRecastQueryFilter FilterPreferredFacing; }
FMyRecastQueryFilter is a subclass of FRecastQueryFilter, that is setting bIsVirtual true in it's constructor, and overrides passVirtualFilter, getVirtualCost, and CreateCopy() to do the same things as the base classes
as long as your InitializeFilter is called, that should be it, at least to have a custom getVirtualCost implementation
if you need the querier (which I have to imagine you do) then you'll need to move to a dynamic instance
but there be lifecycle questions
start with just getting anything custom returned from that guy and solve the rest later
... the UMyNavigationQueryFilter has a Blueprint, which defines some areas. That UMyNavigationQueryFilter is set both as the Default Query Filter in the AIController, and is used in most or all of the calls to BuildPathfindingQuery
well I have no idea about what the blueprints are gonna do for it
maybe try this on an isolated actor first, get rid of the blueprints
test first in isolation
ok, so, i just set the base class as the filter.
Initialize Filter called, our CreateCopy returns a pointer to 263a3386c00, then it goes to UNavigationQueryFilter::InitializeFilter() and sets up the Areas
sure, sure
This chain is being started by a MoveToLocation that calls BuildPathfindingQuery, which goes into GetQueryFilter
so youve overridden InitializeFilter as something like
UNavigationQueryFilter::InitializeFilter(NavData, Querier, Filter);
Filter.SetFilterImplementation(...);
to retain the superclass implementation
erm can you use Super there?
i dunno, unreal stuff
void UMyNavigationQueryFilter::InitializeFilter(const ANavigationData& NavData, const UObject* Querier, FNavigationQueryFilter& Filter) const
{
#if WITH_RECAST
Filter.SetFilterImplementation(&EMyRecastQueryFilter::FilterPreferredFacing);
#endif // WITH_RECAST
Super::InitializeFilter(NavData, Querier, Filter);
}
wow not that its relevent to solving the problem but... do you actually need WITH_RECAST?
how does that work anyway
i'm guessing that if you don't have the recast module building, that won't be set. it was in the original
ahh right
Probably unnecessary if you're just making this for your own game where you would always have recast :)
probably true yes
yeah that was my thought heh
"just in case we ship without it! you never know!!"
zomg hey, any thoughts here?
its been an all night battle
seems like it would always exist in all environments, unlike say ENABLE_VISLOG or whatever that one was
how far up do I need to scroll?
lol
ill sum it up
the goal is to modify the costs of nav mesh path segments (via detour navmesh polys) based on how much of a rotation will be required to get to it
ah yeah I think I saw the start of the conversation last night :D
the less rotation, from point A to point B, the less cost
the idea is to get down to subclassing dtQueryFilter
yeah this has been about 12 hours now
I haven't dug that deeply into the navigation system but at least it sounds like you're on the right track
...which is really just FRecastQueryFilter
that just takes dtQueryFilter and makes it implement INavigationQueryFilterInterface
the goal is to have getVirtualCost() get called passing in the relevant polys
wait a minute
@atomic coral you dont need the actor
the first point in the navigation path is the actor location
ultimately, the situation as it is right now, is i have three levels of navmesh. You start on one level, you nav to the middle level, and we want you to most likely exit out moving in the same direction you came in
if you enter the middle travelling east, we want you to exit travelling east, even if your goal has changed so that the shortest distance would now be to turn around and go north
because that 90 degree turn will take more time than hitting the exit you're facing
i see so you really do need the properties of the agent
because its not just about whatever path got computed
right, i want to add cost weight depending on other factors that aren't static
we have not yet established that youve got code running in the right place though
right
you have UE_LOG in getVirtualCost(), and it is not executing
just recapping in case zomg or someone else comes in with a completely different idea
because i will absolutely take an idea that doesn't involve changing path costs if it works
like how UNavigationQueryFilter supports "meta filters"
how complex are your levels? because a basic waypoint system comes to mind lol
yeah wtf is a meta filter, and a simple filter
i think a simple filter just changes those UPROPERTY on UNavigationQueryFilter and thats it
and a meta filter just chooses a UNavigationQueryFilter subclass to use based on the querier (controller)
ok, some of that makes sense when you explain it with a purpose
but then the GetQueryFilter of UNavigationQueryFilter is what goes from UNavigationQueryFilter to FNavQueryFilter (by way of a FSharedConstNavQueryFilter which is a const TSharedPtr)
and its not virtual
which means you must use the cache system
it calls InitializeFilter() to prepare your instance for a particular filter class, and then it goes a level of indirection down to an Implementation
FNavigationQueryFilter is really just a wrapper, apparently
SetFilterImplementation() accepts a INavigationQueryFilterInterface, and its this which would inherit from dtQueryFilter
OK, so, this run BuildPathfindingQuery hits GetQueryFilter(), which calls InitializeFilter, and that sets me up with my filter at e086980 .. and then it returns some other filter on the other side of the planet address wise
the only usage is here
in GetQueryFilter() as you say
it cant return anything but the SharedFilter that comes out of InitializerFilter
well assuming that Get() is returning a persistent pointer
it is dereferenced and then referenced.... ehm
should be mutable in place right?
it has to be, because the only reference to this in the codebase, is itself exactly what we want
other than instantiating something there to convey the Querier
here they use some static instances
i think possibly the debugger is tripping you up. if you are just jumping from place to place with breakpoints, perhaps there's other instances that arent using your AAIController
There's nothing in this setup except for the AI, it's pawn, and some world decorations
what is the relationship between the UNavigationQueryFilter and the FNavigationQueryFilter?
Got this in a task
And I can see the task firing both in the Behaviour Tree and characters doing stuff in game
Any idea why the ticks aren't firing?
I don't remember if tasks tick by default, did you change the settings on the node to have it tick?
They were set to 0.0 for interval but raising that doesn't seem to have affected it. I'm not seeing any option for ticking.
Both the character and AI controller have tick enabled.
You're sure that the task has not finished, and is being reached in the tree?
Its lit up in the tree. It finishes when they reach the location which its definitely not doing in a single frame.
Actually gonna double check that.
That's odd. Definitely should be ticking then.
Okay some of them are finishing. There's 25 characters though and definitely not 25 strings being printed.
Yeah just tested with a single character. When he wasn't close enough to trigger the finish node it still wasn't hitting tick.
And when his pathfinding breaks (which is what I need the tick for) it does actually count the task's runtime up.
I can't find any info about how to make flying AI π¦ Just something like Cacodemon from Doom. Any tips ?
Depends really on complexity of your levels and how it needs to behave
at simplest it could literally just follow your regular navmesh except in the air
if it uses CMC, turn off gravity
in CMC settings
or set its movement mode to flying, that would probably be more sensible lol
so, disable "can walk" and enable "can fly" ?
cuz I tried just enabling "can fly" in addition to other modes and it still drops to the ground
or do I have to disable gravity regardless ?
I'm really pulling for all of you trying to customize the NavFilter. My first foray into UE C++ took me into the navigation code, and it's nuts.
I have this AI setup already which seems to work but I'm trying to convert this to be not state-based due to some of your recommendation that BT's strength really comes in when you stop thinking about it as a state machine.
So I've made this version, which has all the same behavior but I'm missing the investigate--
Investigate in the original triggers when the AI hears something. How do I communicate this to the BT?
It seems like I need to push a "heard something event" and then maybe clear it in the BT side so it doesn't create bad behavior later. (The agent is supposed to walk over to the spot they heard something and then hang out for a little before going back to patrolling)
but that sounds a lot like state machine transitions π€£
Any recommendations on how to architect this to add the investigate? Am I thinking about BTs right yet? π€£
Feels like I should clear the blackboard value after "consuming" it