Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intended pattern for executing GOAP plans #5

Closed
shadowndacorner opened this issue Jan 13, 2024 · 3 comments
Closed

intended pattern for executing GOAP plans #5

shadowndacorner opened this issue Jan 13, 2024 · 3 comments
Labels
question Further information is requested

Comments

@shadowndacorner
Copy link

shadowndacorner commented Jan 13, 2024

First off, great work on this library!

I'm a bit confused as to the intended pattern for actually executing the plans that come out of this GOAP implementation. If I'm understanding the API correctly, it seems like the apply_effects function may run more than once as part of the pathfinding process. That would seemingly make it a poor fit to hook into for eg updating an agent's nav target, or having them attack another agent, which are operations you only want to execute when you have a full plan.

Is my understanding here accurate, or am I misunderstanding how your implementation works? I'm also not seeing a way to get eg a queue of actions out of the planner, but maybe apply_effects is intended to work as essentially a visitor for that purpose?

Edit: Just noticed the dry_run argument - not sure how I missed that haha. Is that meant to differentiate between the planning process and the execution process? If so, is the blackboard meant to contain a reference to the relevant agent/actor/etc, with the planner and actions being single-instance for the application, or are they meant to be instanced for each agent? If the former, is the planner thread-safe?

@linkdd
Copy link
Owner

linkdd commented Jan 13, 2024

Hi, Thanks for the feedback 🙂

it seems like the apply_effects function may run more than once as part of the pathfinding process.

Yes, during the "planning phase", the apply_effects() will be called. More than once.
A copy of the initial state will be made, and mutated via the apply_effects() until it is equal to the final state (the goal).

The real blackboard is left unmutated once the plan is found.

Just noticed the dry_run argument - not sure how I missed that haha.

It's ok lol I only added it in the v0.3.0 for the specific problem you mentioned. During the planning phase, this argument will be true, during the plan execution it will be false.

is the blackboard meant to contain a reference to the relevant agent/actor/etc

It's up to you. The actions can have a state (private members, a constructor, other methods, etc...). But the blackboard could hold that state as well.

I am using EnTT as an ECS. My blackboard contains a reference to the global game state, while my actions contain a reference to a view (iterable collection of entities with specific components). If the dry_run argument is false, i will iterate over that view to apply changes to both the global game state and local state of entities.

I also make use of EnTT's event dispatcher to implement a message bus, so my actions can send some messages that are picked up later on.

is the planner thread-safe?

The planner works on a copy of the initial state. The only problem might be the actions. If your actions hold some state and are not thread-safe, and you share them between multiple planners (since they are basically std::shared_ptr when they should be std::unique_ptr but I failed to implement that because they are a pain to work with, cf this reddit thread).

Something like this:

auto stateful_action = std::make_shared<my_stateful_action>(...);
auto plan1 = planner<blackboard_type>(std::vector{stateful_action}, initial1, goal1);
auto plan2 = planner<blackboard_type>(std::vector{stateful_action}, initial2, goal2);

But if your actions are self-contained, stateless, or thread-safe, then there should be no problem.

I hope this helps 🙂

@linkdd linkdd added the question Further information is requested label Jan 13, 2024
@linkdd
Copy link
Owner

linkdd commented Jan 14, 2024

FYI: I decided to force myself to use std::unique_ptr instead of std::shared_ptr, I think I found a satisfying solution. More information in the PR #6

As a result, now the planner owns all the data that are given to it. Making it thread-safe.

@linkdd
Copy link
Owner

linkdd commented Jan 19, 2024

I'm closing this issue since it has been resolved.

If you have any further question, don't hesitate to open a discussion 🙂

@linkdd linkdd closed this as completed Jan 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants