Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Plugins/GOAPNPC/GOAPNPC.uplugin
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"FileVersion": 3,
"Version": 2,
"VersionName": "2.1",
"VersionName": "2.2",
"FriendlyName": "GOAP NPC",
"Description": "Goal-Oriented Action Planning for Non-Player Characters",
"Category": "AI",
Expand All @@ -23,5 +23,11 @@
"Win64"
]
}
],
"Plugins": [
{
"Name": "GameplayTagsEditor",
"Enabled": true
}
]
}
9 changes: 7 additions & 2 deletions Plugins/GOAPNPC/Source/GOAPNPC/GOAPNPC.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public GOAPNPC(ReadOnlyTargetRules Target) : base(Target)
new string[]
{
"Core",
"GameplayTags",
// ... add other public dependencies that you statically link with here ...
}
);
Expand All @@ -47,8 +48,12 @@ public GOAPNPC(ReadOnlyTargetRules Target) : base(Target)
// ... add private dependencies that you statically link with here ...
}
);



if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("GameplayTagsEditor");
}

DynamicallyLoadedModuleNames.AddRange(
new string[]
{
Expand Down
65 changes: 48 additions & 17 deletions Plugins/GOAPNPC/Source/GOAPNPC/Private/GOAPAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,95 @@
*/
#include "GOAPAction.h"

#if WITH_EDITORONLY_DATA
#include "GameplayTagsEditorModule.h"

void FAtom::PostSerialize(const FArchive& Ar)
{
if (Ar.IsLoading() && !name_DEPRECATED.IsEmpty())
{
FString tagName = TEXT("GOAP.") + name_DEPRECATED;
tag = UGameplayTagsManager::Get().RequestGameplayTag(FName(tagName), false);
if (!tag.IsValid())
{
IGameplayTagsEditorModule& tagsEditor = IGameplayTagsEditorModule::Get();
bool result = tagsEditor.AddNewGameplayTagToINI(tagName);

tag = UGameplayTagsManager::Get().RequestGameplayTag(FName(tagName));
if (tag.IsValid())
{
name_DEPRECATED = "";
}
else
{
UE_LOG(LogTemp, Fatal, TEXT("Can't get Gameplay tag for (%s)"), *tagName);
}
}
}

}
#endif // WITH_EDITORONLY_DATA

UGOAPAction::UGOAPAction() {}

void UGOAPAction::create_P_E()
{
for (FAtom itP : preconditions)
for (FAtom& itP : preconditions)
{
wsPreconditions.addAtom(itP.name, itP.value);
wsPreconditions.addAtom(itP.tag, itP.value);
}
for (FAtom itE : effects)

for (FAtom& itE : effects)
{
wsEffects.addAtom(itE.name, itE.value);
wsEffects.addAtom(itE.tag, itE.value);
}
if (targetsType == NULL)

if (targetsType == nullptr)
{
UE_LOG(LogTemp, Warning, TEXT("Targets' type of '%s' action are not defined."), *name);
}
}

TArray<AActor*> UGOAPAction::getTargetsList(APawn* p)
TArray<AActor*> UGOAPAction::getTargetsList(APawn* p) const
{
TArray<AActor*> actorsFound;
// AVOID CRASHES, checking if targetsType is empty or not!
UGameplayStatics::GetAllActorsOfClass(p->GetWorld(), targetsType, actorsFound);
return actorsFound;
}

bool UGOAPAction::operator==(UGOAPAction& a)
bool UGOAPAction::operator==(const UGOAPAction& a) const
{
return this->cost == a.getCost() && target == a.getTarget() && wsPreconditions == a.getPreconditions() && wsEffects == a.getEffects();
}

bool UGOAPAction::operator!=(UGOAPAction& a)
bool UGOAPAction::operator!=(const UGOAPAction& a) const
{
return !(*this == a);
}

// GETS

FString UGOAPAction::getName()
FString UGOAPAction::getName() const
{
return this->name;
return name;
}

float UGOAPAction::getCost()
float UGOAPAction::getCost() const
{
return this->cost;
return cost;
}

AActor* UGOAPAction::getTarget()
AActor* UGOAPAction::getTarget() const
{
return target;
}

GOAPWorldState UGOAPAction::getPreconditions()
const GOAPWorldState& UGOAPAction::getPreconditions() const
{
return wsPreconditions;
}

GOAPWorldState UGOAPAction::getEffects()
const GOAPWorldState& UGOAPAction::getEffects() const
{
return wsEffects;
}
Expand All @@ -73,7 +104,7 @@ GOAPWorldState UGOAPAction::getEffects()

void UGOAPAction::setName(FString n)
{
this->name = n;
name = n;
}

void UGOAPAction::setCost(float c)
Expand Down
20 changes: 10 additions & 10 deletions Plugins/GOAPNPC/Source/GOAPNPC/Private/GOAPController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ void AGOAPController::BeginPlay()

// Loads Current World.
for (FAtom atom : currentWorld)
wsCurrentWorld.addAtom(atom.name, atom.value);
wsCurrentWorld.addAtom(atom.tag, atom.value);

// Loads Desired World.
for (FAtom atom : desiredWorld)
wsDesiredWorld.addAtom(atom.name, atom.value);
wsDesiredWorld.addAtom(atom.tag, atom.value);

// Loads actions' preconditions and effects.
for (UGOAPAction* a : auxActions)
Expand Down Expand Up @@ -112,7 +112,7 @@ void AGOAPController::setGoal(const TArray<FAtom>& newGoal)
void AGOAPController::updateGoal(const TArray<FAtom>& atoms)
{
for (FAtom atom : atoms)
wsDesiredWorld.addAtom(atom.name, atom.value);
wsDesiredWorld.addAtom(atom.tag, atom.value);
}

void AGOAPController::setCurrentWorld(const TArray<FAtom>& newCurrentWorld)
Expand All @@ -124,26 +124,26 @@ void AGOAPController::setCurrentWorld(const TArray<FAtom>& newCurrentWorld)
void AGOAPController::updateCurrentWorld(const TArray<FAtom>& atoms)
{
for (FAtom atom : atoms)
wsCurrentWorld.addAtom(atom.name, atom.value);
wsCurrentWorld.addAtom(atom.tag, atom.value);
}

TArray<FAtom> AGOAPController::getCurrentWorldStateAtoms()
TArray<FAtom> AGOAPController::getCurrentWorldStateAtoms() const
{
TArray<FAtom> worldStateAtoms;
for (auto atoms : wsCurrentWorld.getAtoms())
for (auto atom : wsCurrentWorld.getAtoms())
{
worldStateAtoms.Add({ atoms.first, atoms.second });
worldStateAtoms.Add({ atom.Key, atom.Value });
}

return worldStateAtoms;
}

TArray<FAtom> AGOAPController::getDesiredWorldStateAtoms()
TArray<FAtom> AGOAPController::getDesiredWorldStateAtoms() const
{
TArray<FAtom> worldStateAtoms;
for (auto atoms : wsDesiredWorld.getAtoms())
for (auto atom : wsDesiredWorld.getAtoms())
{
worldStateAtoms.Add({ atoms.first, atoms.second });
worldStateAtoms.Add({ atom.Key, atom.Value });
}

return worldStateAtoms;
Expand Down
29 changes: 14 additions & 15 deletions Plugins/GOAPNPC/Source/GOAPNPC/Private/GOAPNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,48 @@

GOAPNode::GOAPNode()
{
action = NULL;
g = 0;
h = 0;
}

GOAPNode::GOAPNode(UGOAPAction* a)
{
action = a;
if (a != NULL)g = a->getCost();
else g = 0;
g = a ? a->getCost() : 0;
h = 0;
}

bool GOAPNode::operator==(GOAPNode n)
bool GOAPNode::operator==(const GOAPNode& n) const
{
return action == n.getAction();
}


GOAPWorldState GOAPNode::getWorld()
const GOAPWorldState& GOAPNode::getWorld() const
{
return world;
}

int GOAPNode::getH()
int GOAPNode::getH() const
{
return h;
}

float GOAPNode::getG()
float GOAPNode::getG() const
{
return g;
}

float GOAPNode::getF()
float GOAPNode::getF() const
{
return g + h;
}

int GOAPNode::getParent()
int GOAPNode::getParent() const
{
return parent;
}

UGOAPAction* GOAPNode::getAction()
UGOAPAction* GOAPNode::getAction() const
{
return action;
}
Expand All @@ -72,12 +69,14 @@ void GOAPNode::setH(GOAPWorldState w)
{
for (auto it : world.getAtoms())
{
auto aux = w.getAtoms().find(it.first);
if (aux != w.getAtoms().end())
auto* value = w.getAtoms().Find(it.Key);
if (value)
{
if (it.second != aux->second) ++h;
if (*value != it.Value)
++h;
}
else ++h;
else
++h;
}
}

Expand Down
19 changes: 11 additions & 8 deletions Plugins/GOAPNPC/Source/GOAPNPC/Private/GOAPPlanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ GOAPPlanner::GOAPPlanner(GOAPWorldState* c, GOAPWorldState* g, const TArray<UGOA
actions = a;
}

GOAPNode GOAPPlanner::lowestFinList(const TArray<GOAPNode>& opList)
const GOAPNode* GOAPPlanner::lowestFinList(const TArray<GOAPNode>& opList) const
{
GOAPNode node;
const GOAPNode* node = nullptr;

float minF = MAX_FLT;
for (GOAPNode n : opList)
for (const GOAPNode& n : opList)
{
if ((n.getF()) < minF)
{
node = n;
node = &n;
minF = n.getF();
}
}

return node;
}

bool containsNode(GOAPNode node, const TArray<GOAPNode>& list)
bool containsNode(const GOAPNode& node, const TArray<GOAPNode>& list)
{
bool contains = false;
for (GOAPNode n : list)
for (const GOAPNode& n : list)
{
if (n == node)
{
Expand Down Expand Up @@ -80,7 +80,10 @@ TArray<UGOAPAction*> GOAPPlanner::generatePlan(APawn* p)
{
TArray<UGOAPAction*> sol;

GOAPNode start; start.setWorld(*currentWorld); start.setParent(-1);
GOAPNode start;
start.setWorld(*currentWorld);
start.setParent(-1);

GOAPNode last;
openList.Empty();
closedList.Empty();
Expand All @@ -91,7 +94,7 @@ TArray<UGOAPAction*> GOAPPlanner::generatePlan(APawn* p)
// Search and create the cheapest path between actions having into account their preconditions, effects and cost.
while (continues)
{
GOAPNode current = lowestFinList(openList);
GOAPNode current = *lowestFinList(openList);
openList.Remove(current);
closedList.Push(current);
int pos = closedList.Num() - 1;
Expand Down
Loading