From eaa28844c9352eba3498b5f33103e0b7832dbcf3 Mon Sep 17 00:00:00 2001 From: Duion Date: Fri, 12 Aug 2016 20:39:56 +0200 Subject: [PATCH] BadBehavior added --- .../BadBehavior/composite/ActiveSelector.cpp | 132 ++++++++ .../BadBehavior/composite/ActiveSelector.h | 92 ++++++ .../source/BadBehavior/composite/Parallel.cpp | 175 ++++++++++ .../source/BadBehavior/composite/Parallel.h | 97 ++++++ .../BadBehavior/composite/RandomSelector.cpp | 68 ++++ .../BadBehavior/composite/RandomSelector.h | 62 ++++ .../source/BadBehavior/composite/Selector.cpp | 54 ++++ .../source/BadBehavior/composite/Selector.h | 60 ++++ .../source/BadBehavior/composite/Sequence.cpp | 55 ++++ .../source/BadBehavior/composite/Sequence.h | 60 ++++ Engine/source/BadBehavior/core/Branch.cpp | 66 ++++ Engine/source/BadBehavior/core/Branch.h | 53 +++ Engine/source/BadBehavior/core/Composite.cpp | 110 +++++++ Engine/source/BadBehavior/core/Composite.h | 70 ++++ Engine/source/BadBehavior/core/Core.cpp | 161 ++++++++++ Engine/source/BadBehavior/core/Core.h | 151 +++++++++ Engine/source/BadBehavior/core/Decorator.cpp | 106 ++++++ Engine/source/BadBehavior/core/Decorator.h | 68 ++++ Engine/source/BadBehavior/core/Runner.cpp | 278 ++++++++++++++++ Engine/source/BadBehavior/core/Runner.h | 140 ++++++++ Engine/source/BadBehavior/core/Signal.cpp | 168 ++++++++++ Engine/source/BadBehavior/core/Signal.h | 97 ++++++ Engine/source/BadBehavior/core/Stepper.cpp | 71 +++++ Engine/source/BadBehavior/core/Stepper.h | 43 +++ Engine/source/BadBehavior/core/behavior.cpp | 106 ++++++ Engine/source/BadBehavior/core/behavior.h | 87 +++++ .../BadBehavior/decorator/FailAlways.cpp | 51 +++ .../source/BadBehavior/decorator/FailAlways.h | 61 ++++ .../source/BadBehavior/decorator/Inverter.cpp | 54 ++++ .../source/BadBehavior/decorator/Inverter.h | 62 ++++ Engine/source/BadBehavior/decorator/Loop.cpp | 120 +++++++ Engine/source/BadBehavior/decorator/Loop.h | 90 ++++++ .../source/BadBehavior/decorator/Monitor.cpp | 54 ++++ Engine/source/BadBehavior/decorator/Monitor.h | 61 ++++ Engine/source/BadBehavior/decorator/Root.cpp | 75 +++++ Engine/source/BadBehavior/decorator/Root.h | 73 +++++ .../BadBehavior/decorator/SucceedAlways.cpp | 51 +++ .../BadBehavior/decorator/SucceedAlways.h | 61 ++++ .../source/BadBehavior/decorator/Ticker.cpp | 136 ++++++++ Engine/source/BadBehavior/decorator/Ticker.h | 89 ++++++ Engine/source/BadBehavior/leaf/RandomWait.cpp | 125 ++++++++ Engine/source/BadBehavior/leaf/RandomWait.h | 83 +++++ Engine/source/BadBehavior/leaf/ScriptEval.cpp | 94 ++++++ Engine/source/BadBehavior/leaf/ScriptEval.h | 75 +++++ Engine/source/BadBehavior/leaf/ScriptFunc.cpp | 121 +++++++ Engine/source/BadBehavior/leaf/ScriptFunc.h | 79 +++++ .../BadBehavior/leaf/ScriptedBehavior.cpp | 83 +++++ .../BadBehavior/leaf/ScriptedBehavior.h | 56 ++++ Engine/source/BadBehavior/leaf/SubTree.cpp | 76 +++++ Engine/source/BadBehavior/leaf/SubTree.h | 56 ++++ Engine/source/BadBehavior/leaf/Wait.cpp | 115 +++++++ Engine/source/BadBehavior/leaf/Wait.h | 80 +++++ .../source/BadBehavior/leaf/WaitForSignal.cpp | 145 +++++++++ .../source/BadBehavior/leaf/WaitForSignal.h | 114 +++++++ .../leaf/compiled/followBehaviorAction.cpp | 109 +++++++ .../leaf/compiled/followBehaviorAction.h | 52 +++ .../BadBehavior/tools/BTUndoActions.cpp | 135 ++++++++ .../source/BadBehavior/tools/BTUndoActions.h | 77 +++++ .../BadBehavior/tools/guiBTViewCtrl.cpp | 301 ++++++++++++++++++ .../source/BadBehavior/tools/guiBTViewCtrl.h | 45 +++ .../Empty/buildFiles/config/projectCode.conf | 1 + .../Full/buildFiles/config/projectCode.conf | 1 + Tools/CMake/torque3d.cmake | 7 + 63 files changed, 5698 insertions(+) create mode 100644 Engine/source/BadBehavior/composite/ActiveSelector.cpp create mode 100644 Engine/source/BadBehavior/composite/ActiveSelector.h create mode 100644 Engine/source/BadBehavior/composite/Parallel.cpp create mode 100644 Engine/source/BadBehavior/composite/Parallel.h create mode 100644 Engine/source/BadBehavior/composite/RandomSelector.cpp create mode 100644 Engine/source/BadBehavior/composite/RandomSelector.h create mode 100644 Engine/source/BadBehavior/composite/Selector.cpp create mode 100644 Engine/source/BadBehavior/composite/Selector.h create mode 100644 Engine/source/BadBehavior/composite/Sequence.cpp create mode 100644 Engine/source/BadBehavior/composite/Sequence.h create mode 100644 Engine/source/BadBehavior/core/Branch.cpp create mode 100644 Engine/source/BadBehavior/core/Branch.h create mode 100644 Engine/source/BadBehavior/core/Composite.cpp create mode 100644 Engine/source/BadBehavior/core/Composite.h create mode 100644 Engine/source/BadBehavior/core/Core.cpp create mode 100644 Engine/source/BadBehavior/core/Core.h create mode 100644 Engine/source/BadBehavior/core/Decorator.cpp create mode 100644 Engine/source/BadBehavior/core/Decorator.h create mode 100644 Engine/source/BadBehavior/core/Runner.cpp create mode 100644 Engine/source/BadBehavior/core/Runner.h create mode 100644 Engine/source/BadBehavior/core/Signal.cpp create mode 100644 Engine/source/BadBehavior/core/Signal.h create mode 100644 Engine/source/BadBehavior/core/Stepper.cpp create mode 100644 Engine/source/BadBehavior/core/Stepper.h create mode 100644 Engine/source/BadBehavior/core/behavior.cpp create mode 100644 Engine/source/BadBehavior/core/behavior.h create mode 100644 Engine/source/BadBehavior/decorator/FailAlways.cpp create mode 100644 Engine/source/BadBehavior/decorator/FailAlways.h create mode 100644 Engine/source/BadBehavior/decorator/Inverter.cpp create mode 100644 Engine/source/BadBehavior/decorator/Inverter.h create mode 100644 Engine/source/BadBehavior/decorator/Loop.cpp create mode 100644 Engine/source/BadBehavior/decorator/Loop.h create mode 100644 Engine/source/BadBehavior/decorator/Monitor.cpp create mode 100644 Engine/source/BadBehavior/decorator/Monitor.h create mode 100644 Engine/source/BadBehavior/decorator/Root.cpp create mode 100644 Engine/source/BadBehavior/decorator/Root.h create mode 100644 Engine/source/BadBehavior/decorator/SucceedAlways.cpp create mode 100644 Engine/source/BadBehavior/decorator/SucceedAlways.h create mode 100644 Engine/source/BadBehavior/decorator/Ticker.cpp create mode 100644 Engine/source/BadBehavior/decorator/Ticker.h create mode 100644 Engine/source/BadBehavior/leaf/RandomWait.cpp create mode 100644 Engine/source/BadBehavior/leaf/RandomWait.h create mode 100644 Engine/source/BadBehavior/leaf/ScriptEval.cpp create mode 100644 Engine/source/BadBehavior/leaf/ScriptEval.h create mode 100644 Engine/source/BadBehavior/leaf/ScriptFunc.cpp create mode 100644 Engine/source/BadBehavior/leaf/ScriptFunc.h create mode 100644 Engine/source/BadBehavior/leaf/ScriptedBehavior.cpp create mode 100644 Engine/source/BadBehavior/leaf/ScriptedBehavior.h create mode 100644 Engine/source/BadBehavior/leaf/SubTree.cpp create mode 100644 Engine/source/BadBehavior/leaf/SubTree.h create mode 100644 Engine/source/BadBehavior/leaf/Wait.cpp create mode 100644 Engine/source/BadBehavior/leaf/Wait.h create mode 100644 Engine/source/BadBehavior/leaf/WaitForSignal.cpp create mode 100644 Engine/source/BadBehavior/leaf/WaitForSignal.h create mode 100644 Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.cpp create mode 100644 Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.h create mode 100644 Engine/source/BadBehavior/tools/BTUndoActions.cpp create mode 100644 Engine/source/BadBehavior/tools/BTUndoActions.h create mode 100644 Engine/source/BadBehavior/tools/guiBTViewCtrl.cpp create mode 100644 Engine/source/BadBehavior/tools/guiBTViewCtrl.h diff --git a/Engine/source/BadBehavior/composite/ActiveSelector.cpp b/Engine/source/BadBehavior/composite/ActiveSelector.cpp new file mode 100644 index 000000000..cf33f78a1 --- /dev/null +++ b/Engine/source/BadBehavior/composite/ActiveSelector.cpp @@ -0,0 +1,132 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "ActiveSelector.h" + +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Active selector node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(ActiveSelector); + +ActiveSelector::ActiveSelector() + : mRecheckFrequency(0) +{ +} + +Task *ActiveSelector::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new ActiveSelectorTask(*this, owner, runner); +} + +void ActiveSelector::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "recheckFrequency", TypeS32, Offset(mRecheckFrequency, ActiveSelector), + "@brief The minimum time period in milliseconds to wait between re-evaluations of higher priority branches."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +//------------------------------------------------------------------------------ +// Active selector task +//------------------------------------------------------------------------------ +ActiveSelectorTask::ActiveSelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mRecheckTime(0) +{ +} + +void ActiveSelectorTask::onInitialize() +{ + Parent::onInitialize(); + + if(mBranches.empty()) + { + for (VectorPtr::iterator i = mChildren.begin(); i != mChildren.end(); ++i) + { + mBranches.push_back(BehaviorTreeBranch(*i)); + } + } + + mCurrentBranch = mBranches.begin(); + mRunningBranch = mBranches.end(); + mRecheckTime = 0; +} + + +Task* ActiveSelectorTask::update() +{ + // empty node, bail + if(mBranches.empty()) + { + mStatus = INVALID; + return NULL; + } + + // is it time to re-check higher priority branches? + if(Sim::getCurrentTime() >= mRecheckTime) + { + // pick highest priority branch + mCurrentBranch = mBranches.begin(); + + // determine the next recheck time + mRecheckTime = Sim::getCurrentTime() + static_cast(mNodeRep)->getRecheckFrequency(); + } + + // run a branch, if it fails move on to the next + for(mCurrentBranch; mCurrentBranch != mBranches.end(); ++mCurrentBranch) + { + // reset the branch if it's not the current running branch + if(mCurrentBranch != mRunningBranch) + mCurrentBranch->reset(); + + mStatus = mCurrentBranch->update(); + + if(mStatus == FAILURE) // move on to next + continue; + + if(mStatus == RUNNING || mStatus == SUSPENDED) // track the current running branch + mRunningBranch = mCurrentBranch; + + break; + } + + if( (mStatus != RUNNING && mStatus != SUSPENDED) || mCurrentBranch == mBranches.end() ) + mIsComplete = true; + + return NULL; +} + +Status ActiveSelectorTask::getStatus() +{ + if(mStatus == SUSPENDED && mCurrentBranch != mBranches.end()) + return mCurrentBranch->getStatus(); // suspended branch may have resumed + + return mStatus; +} diff --git a/Engine/source/BadBehavior/composite/ActiveSelector.h b/Engine/source/BadBehavior/composite/ActiveSelector.h new file mode 100644 index 000000000..939979f38 --- /dev/null +++ b/Engine/source/BadBehavior/composite/ActiveSelector.h @@ -0,0 +1,92 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_ACTIVESELECTOR_H_ +#define _BB_ACTIVESELECTOR_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Composite.h" +#endif +#ifndef _BB_BRANCH_H_ +#include "BadBehavior/core/Branch.h" +#endif + +//============================================================================== +// Active Selector +// Re-evaluates its children from the beginning each tick. Lower priority +// children which previously returned RUNNING are resumed if re-selected +// +// ***** TODO - This runs OK, but may need a bit more work +// -- abort previously running branches? +// +//============================================================================== + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Active selector Node + //--------------------------------------------------------------------------- + class ActiveSelector : public CompositeNode + { + typedef CompositeNode Parent; + + protected: + U32 mRecheckFrequency; + + public: + ActiveSelector(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + U32 getRecheckFrequency() const { return mRecheckFrequency; } + + DECLARE_CONOBJECT(ActiveSelector); + }; + + //--------------------------------------------------------------------------- + // Active selector Task + //--------------------------------------------------------------------------- + class ActiveSelectorTask : public CompositeTask + { + typedef CompositeTask Parent; + + protected: + Vector::iterator mRunningBranch; + Vector::iterator mCurrentBranch; + Vector mBranches; + + U32 mRecheckTime; + + virtual void onInitialize(); + virtual Task* update(); + + public: + ActiveSelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + Status getStatus(); +}; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/composite/Parallel.cpp b/Engine/source/BadBehavior/composite/Parallel.cpp new file mode 100644 index 000000000..4b8fce727 --- /dev/null +++ b/Engine/source/BadBehavior/composite/Parallel.cpp @@ -0,0 +1,175 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Parallel.h" + +#include "console/engineAPI.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Parallel node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Parallel); + +Parallel::Parallel() + : mReturnPolicy(REQUIRE_ALL) +{ +} + +ImplementEnumType( ParallelReturnPolicy, + "@brief The policy to use when determining the return status of a parallel node.\n\n" + "@ingroup AI\n\n") + { Parallel::REQUIRE_ALL, "REQUIRE_ALL", "Will return success if all children succeed.\n" + "Will terminate and return failure if one child fails \n"}, + { Parallel::REQUIRE_NONE, "REQUIRE_NONE", "Will return success even if all children fail.\n" }, + { Parallel::REQUIRE_ONE, "REQUIRE_ONE", "Will terminate and return success when one child succeeds.\n" }, +EndImplementEnumType; + +void Parallel::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "returnPolicy", TYPEID< Parallel::ParallelPolicy >(), Offset(mReturnPolicy, Parallel), + "@brief The policy to use when deciding the return status for the parallel sequence."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *Parallel::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new ParallelTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Parallel Task +//------------------------------------------------------------------------------ +ParallelTask::ParallelTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mHasSuccess(false), + mHasFailure(false) +{ +} + +void ParallelTask::onInitialize() +{ + Parent::onInitialize(); + + mHasSuccess = mHasFailure = false; + + if(mBranches.empty()) + { + for (VectorPtr::iterator i = mChildren.begin(); i != mChildren.end(); ++i) + { + mBranches.push_back(BehaviorTreeBranch(*i)); + } + } + else + { + for (Vector::iterator it = mBranches.begin(); it != mBranches.end(); ++it) + { + it->reset(); + } + } +} + +Task* ParallelTask::update() +{ + bool hasRunning = false, hasSuspended = false, hasResume = false; + for (Vector::iterator it = mBranches.begin(); it != mBranches.end(); ++it) + { + Status s = it->getStatus(); + if(s == INVALID || s == RUNNING || s == RESUME) + { + s = it->update(); + + switch(it->getStatus()) + { + case SUCCESS: + mHasSuccess = true; + break; + case FAILURE: + mHasFailure = true; + break; + case RUNNING: + hasRunning = true; + break; + case SUSPENDED: + hasSuspended = true; + break; + case RESUME: + hasResume = true; + break; + } + } + } + + switch(static_cast(mNodeRep)->getReturnPolicy()) + { + // REQUIRE_NONE + // returns SUCCESS when all children have finished irrespective of their return status. + case Parallel::REQUIRE_NONE: + mStatus = hasResume ? RESUME : ( hasRunning ? RUNNING : ( hasSuspended ? SUSPENDED : SUCCESS ) ); + break; + + // REQUIRE_ONE + // terminates and returns SUCCESS when any of its children succeed + // returns FAILURE if no children succeed + case Parallel::REQUIRE_ONE: + mStatus = mHasSuccess ? SUCCESS : ( hasResume ? RESUME : ( hasRunning ? RUNNING : ( hasSuspended ? SUSPENDED : FAILURE ) ) ); + break; + + // REQUIRE_ALL + // returns SUCCESS if all of its children succeed. + // terminates and returns failure if any of its children fail + case Parallel::REQUIRE_ALL: + mStatus = mHasFailure ? FAILURE : ( hasResume ? RESUME : ( hasRunning ? RUNNING : ( hasSuspended ? SUSPENDED : SUCCESS ) ) ); + break; + } + + mIsComplete = (mStatus != RUNNING && mStatus != SUSPENDED && mStatus != RESUME); + + return NULL; +} + + +Status ParallelTask::getStatus() +{ + if(mStatus == SUSPENDED) + { + // need to check if the parallel is still suspended. + // A parallel will only report SUSPENDED when all of its children are suspended + for(Vector::iterator it = mBranches.begin(); it != mBranches.end(); ++it) + { + switch(it->getStatus()) + { + case RUNNING: + return RUNNING; + case RESUME: + return RESUME; + } + } + } + return mStatus; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/composite/Parallel.h b/Engine/source/BadBehavior/composite/Parallel.h new file mode 100644 index 000000000..91467b44b --- /dev/null +++ b/Engine/source/BadBehavior/composite/Parallel.h @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_PARALLEL_H_ +#define _BB_PARALLEL_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Composite.h" +#endif + +#ifndef _BB_BRANCH_H_ +#include "BadBehavior/core/Branch.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Parallel sequence node + // Runs all of its children irrespective of their return status + // The final return status depends on the chosen policy + // (not a true parallel, as branches are actually evaluated sequentially) + //--------------------------------------------------------------------------- + class Parallel: public CompositeNode + { + typedef CompositeNode Parent; + + public: + // parallel return policies + enum ParallelPolicy + { + REQUIRE_NONE, + REQUIRE_ONE, + REQUIRE_ALL, + }; + + protected: + ParallelPolicy mReturnPolicy; + + public: + Parallel(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + ParallelPolicy getReturnPolicy() const { return mReturnPolicy; } + + DECLARE_CONOBJECT(Parallel); + }; + + //--------------------------------------------------------------------------- + // Parallel Task + //--------------------------------------------------------------------------- + class ParallelTask: public CompositeTask + { + typedef CompositeTask Parent; + + protected: + Vector mBranches; + + bool mHasSuccess, mHasFailure; + + virtual void onInitialize(); + virtual Task* update(); + + public: + ParallelTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual Status getStatus(); + }; + +} // namespace BadBehavior + +// make the return policy enum accessible from script +typedef BadBehavior::Parallel::ParallelPolicy ParallelReturnPolicy; +DefineEnumType( ParallelReturnPolicy ); + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/composite/RandomSelector.cpp b/Engine/source/BadBehavior/composite/RandomSelector.cpp new file mode 100644 index 000000000..de5abffc8 --- /dev/null +++ b/Engine/source/BadBehavior/composite/RandomSelector.cpp @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "RandomSelector.h" + +#include "math/mMathFn.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Random selector node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(RandomSelector); + +Task *RandomSelector::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new RandomSelectorTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Random selector task +//------------------------------------------------------------------------------ +RandomSelectorTask::RandomSelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void RandomSelectorTask::onInitialize() +{ + Parent::onInitialize(); + + // randomize the order of our child tasks + VectorPtr randomChildren; + + while(mChildren.size() > 0) + { + U32 index = mRandI(0, mChildren.size() - 1); + Task* child = mChildren[index]; + randomChildren.push_back(child); + mChildren.erase_fast(index); + } + + mChildren = randomChildren; + + // normal init + mCurrentChild = mChildren.begin(); + if(mCurrentChild != mChildren.end()) + (*mCurrentChild)->reset(); +} diff --git a/Engine/source/BadBehavior/composite/RandomSelector.h b/Engine/source/BadBehavior/composite/RandomSelector.h new file mode 100644 index 000000000..ed2417731 --- /dev/null +++ b/Engine/source/BadBehavior/composite/RandomSelector.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_RANDOMSELECTOR_H_ +#define _BB_RANDOMSELECTOR_H_ + +#ifndef _BB_SELECTOR_H_ +#include "Selector.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Random selector node + // selects its children in a random order until one of them succeeds + //--------------------------------------------------------------------------- + class RandomSelector : public Selector + { + typedef Selector Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(RandomSelector); + }; + + //--------------------------------------------------------------------------- + // Random selector task + //--------------------------------------------------------------------------- + class RandomSelectorTask : public SelectorTask + { + typedef SelectorTask Parent; + + protected: + virtual void onInitialize(); + + public: + RandomSelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/composite/Selector.cpp b/Engine/source/BadBehavior/composite/Selector.cpp new file mode 100644 index 000000000..b62828b5c --- /dev/null +++ b/Engine/source/BadBehavior/composite/Selector.cpp @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Selector.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Selector node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Selector); + +Task *Selector::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new SelectorTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Selector task +//------------------------------------------------------------------------------ +SelectorTask::SelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void SelectorTask::onChildComplete(Status s) +{ + mStatus = s; + + // if child failed, move on to the next child + if(mStatus == FAILURE) + ++mCurrentChild; + else + mIsComplete = true; +} diff --git a/Engine/source/BadBehavior/composite/Selector.h b/Engine/source/BadBehavior/composite/Selector.h new file mode 100644 index 000000000..1a2386c33 --- /dev/null +++ b/Engine/source/BadBehavior/composite/Selector.h @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SELECTOR_H_ +#define _BBSELECTOR_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Composite.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Selector Node + //--------------------------------------------------------------------------- + class Selector : public CompositeNode + { + typedef CompositeNode Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(Selector); + }; + + //--------------------------------------------------------------------------- + // Selector Task + //--------------------------------------------------------------------------- + class SelectorTask : public CompositeTask + { + typedef CompositeTask Parent; + + public: + SelectorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/composite/Sequence.cpp b/Engine/source/BadBehavior/composite/Sequence.cpp new file mode 100644 index 000000000..27b87f8bd --- /dev/null +++ b/Engine/source/BadBehavior/composite/Sequence.cpp @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Sequence.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Sequence node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Sequence); + +Task *Sequence::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new SequenceTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Sequence Task +//------------------------------------------------------------------------------ +SequenceTask::SequenceTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void SequenceTask::onChildComplete(Status s) +{ + mStatus = s; + + // if child succeeded, move on to the next child + if(mStatus == SUCCESS) + ++mCurrentChild; + else + mIsComplete = true; +} + diff --git a/Engine/source/BadBehavior/composite/Sequence.h b/Engine/source/BadBehavior/composite/Sequence.h new file mode 100644 index 000000000..49f07b5d1 --- /dev/null +++ b/Engine/source/BadBehavior/composite/Sequence.h @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SEQUENCE_H_ +#define _BB_SEQUENCE_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Composite.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Sequence Node + //--------------------------------------------------------------------------- + class Sequence : public CompositeNode + { + typedef CompositeNode Parent; + + public: + virtual Task* createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(Sequence); + }; + + //--------------------------------------------------------------------------- + // Sequence Task + //--------------------------------------------------------------------------- + class SequenceTask : public CompositeTask + { + typedef CompositeTask Parent; + + public: + SequenceTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Branch.cpp b/Engine/source/BadBehavior/core/Branch.cpp new file mode 100644 index 000000000..fd5c5919e --- /dev/null +++ b/Engine/source/BadBehavior/core/Branch.cpp @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Branch.h" +#include "Stepper.h" + +using namespace BadBehavior; + +BehaviorTreeBranch::BehaviorTreeBranch() + : mRootTask(NULL) +{ +} + +BehaviorTreeBranch::BehaviorTreeBranch(Task *root) + : mRootTask(root), + mStatus(INVALID) +{ +} + +Status BehaviorTreeBranch::getStatus() +{ + if(!mTasks.empty()) + return mTasks.back()->getStatus(); + + return mStatus; +} + +Status BehaviorTreeBranch::update() +{ + if(mRootTask) + { + if(mTasks.empty()) + { + mRootTask->setup(); + mTasks.push_back(mRootTask); + } + } + mStatus = BehaviorTreeStepper::stepThrough(mTasks); + return mStatus; +} + +void BehaviorTreeBranch::reset() +{ + mStatus = INVALID; + mRootTask->reset(); + mTasks.clear(); +} diff --git a/Engine/source/BadBehavior/core/Branch.h b/Engine/source/BadBehavior/core/Branch.h new file mode 100644 index 000000000..4198b524e --- /dev/null +++ b/Engine/source/BadBehavior/core/Branch.h @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_BRANCH_H_ +#define _BB_BRANCH_H_ + +#ifndef _BB_CORE_H_ +#include "Core.h" +#endif + +namespace BadBehavior +{ + // The branch class handles a single execution path in the tree + // Typically used for the tree root and for handling suspension and concurrency + class BehaviorTreeBranch + { + private: + Status mStatus; + Task *mRootTask; + VectorPtr mTasks; + + public: + BehaviorTreeBranch(); + BehaviorTreeBranch(Task *root); + + Status getStatus(); + Status update(); + void reset(); + }; + + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Composite.cpp b/Engine/source/BadBehavior/core/Composite.cpp new file mode 100644 index 000000000..6f3b4d937 --- /dev/null +++ b/Engine/source/BadBehavior/core/Composite.cpp @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Composite.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Base composite node +// override addObject to only allow behavior tree nodes to be added +//------------------------------------------------------------------------------ +void CompositeNode::addObject(SimObject *object) +{ + if(dynamic_cast(object)) + Parent::addObject(object); +} + +bool CompositeNode::acceptsAsChild( SimObject *object ) const +{ + return (dynamic_cast(object)); +} + +//------------------------------------------------------------------------------ +// Base composite task +//------------------------------------------------------------------------------ +CompositeTask::CompositeTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +CompositeTask::~CompositeTask() +{ + while(mChildren.size()) + { + Task *child = mChildren.back(); + mChildren.pop_back(); + if(child) + delete child; + } +} + +void CompositeTask::onInitialize() +{ + if(mChildren.empty()) + { + CompositeNode *node = static_cast(mNodeRep); + for(SimSet::iterator i = node->begin(); i != node->end(); ++i) + { + Task *task = static_cast(*i)->createTask(*mOwner, *mRunner); + if(task) + { + task->setParent(this); + mChildren.push_back(task); + } + } + } + + mStatus = INVALID; + mCurrentChild = mChildren.begin(); + if(mCurrentChild != mChildren.end()) + (*mCurrentChild)->reset(); +} + +void CompositeTask::onTerminate() +{ + mStatus = INVALID; +} + +Task* CompositeTask::update() +{ + // reached the end of child list, we are complete + if (mCurrentChild == mChildren.end()) + mIsComplete = true; + + // task has finished + if( mIsComplete ) + { + // are we latent? + if(mStatus == RUNNING || mStatus == SUSPENDED) + mIsComplete = false; + + return NULL; + } + + // reset the child ready for the next tick + if(mStatus != RUNNING && mStatus != SUSPENDED) + (*mCurrentChild)->reset(); + + // return child + return (*mCurrentChild); +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Composite.h b/Engine/source/BadBehavior/core/Composite.h new file mode 100644 index 000000000..47bc236d3 --- /dev/null +++ b/Engine/source/BadBehavior/core/Composite.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_COMPOSITE_H_ +#define _BB_COMPOSITE_H_ + +#ifndef _BB_CORE_H_ +#include "Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Composite node base class - for nodes with children + //--------------------------------------------------------------------------- + class CompositeNode : public Node + { + typedef Node Parent; + + public: + // override addObject and acceptsAsChild to only allow behavior tree nodes to be added as children + virtual void addObject(SimObject *obj); + virtual bool acceptsAsChild( SimObject *object ) const; + }; + + //--------------------------------------------------------------------------- + // Composite task base class + //--------------------------------------------------------------------------- + class CompositeTask : public Task + { + typedef Task Parent; + + protected: + // vector of pointers to child tasks + VectorPtr mChildren; + + // the current child task + VectorPtr::iterator mCurrentChild; + + virtual void onInitialize(); + virtual void onTerminate(); + virtual Task* update(); + + public: + CompositeTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~CompositeTask(); + }; + +} // namespace BadBehavior + +#endif diff --git a/Engine/source/BadBehavior/core/Core.cpp b/Engine/source/BadBehavior/core/Core.cpp new file mode 100644 index 000000000..172397879 --- /dev/null +++ b/Engine/source/BadBehavior/core/Core.cpp @@ -0,0 +1,161 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Core.h" +#include "Runner.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +bool gInBtEditor = false; + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// script enum for return type +//------------------------------------------------------------------------------ +ImplementEnumType( BehaviorReturnType, + "@brief The return status for a behavior.\n\n" + "@ingroup AI\n\n") + // not needed script side + //{ BadBehavior::INVALID, "INVALID", "The behavior could not be evaluated.\n" }, + { BadBehavior::SUCCESS, "SUCCESS", "The behavior succeeded.\n" }, + { BadBehavior::FAILURE, "FAILURE", "The behavior failed.\n" }, + { BadBehavior::RUNNING, "RUNNING", "The behavior is still running.\n" }, + // not needed script side + //{ BadBehavior::SUSPENDED, "SUSPENDED", "The behavior has been suspended.\n" }, + //{ BadBehavior::RESUME, "RESUME", "The behavior is resuming from suspended.\n" } +EndImplementEnumType; + + +//================================LeafNode====================================== + +//------------------------------------------------------------------------------ +// don't allow objects to be added +//------------------------------------------------------------------------------ +void LeafNode::addObject(SimObject *object) +{ +} + +bool LeafNode::acceptsAsChild( SimObject *object ) const +{ + return false; +} + + +//==================================Task======================================== + +Task::Task(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : mStatus(INVALID), + mIsComplete(false), + mNodeRep(&node), + mOwner(&owner), + mRunner(&runner), + mParent(NULL) +{ +} + +Task::~Task() +{ +} + +void Task::onInitialize() +{ +} + +void Task::onTerminate() +{ +} + +Task* Task::tick() +{ + PROFILE_SCOPE(Task_Tick); + + return update(); +} + +void Task::setup() +{ + PROFILE_SCOPE(Task_setup); + + if(mStatus != RUNNING && mStatus != SUSPENDED) + onInitialize(); + + mIsComplete = false; +} + +void Task::finish() +{ + if(mIsComplete) + onTerminate(); +} + +void Task::reset() +{ + mStatus = INVALID; +} + +Status Task::getStatus() +{ + return mStatus; +} + +void Task::setStatus(Status newStatus) +{ + mStatus = newStatus; +} + +void Task::setParent(Task *parent) +{ + mParent = parent; +} + +Task *Task::getParent() +{ + return mParent; +} + +void Task::onChildComplete(Status) +{ +} + +void Task::onResume() +{ + if(mStatus == SUSPENDED) + mStatus = RESUME; + + //Con::warnf("onResume %s", + // mNodeRep->getIdString()); +} + +DefineEngineFunction(onBehaviorTreeEditorStart, void, (),, + "@brief Notify the engine that the behavior tree editor is active") +{ + gInBtEditor = true; +} + + +DefineEngineFunction(onBehaviorTreeEditorStop, void, (),, + "@brief Notify the engine that the behavior tree editor has finished") +{ + gInBtEditor = false; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Core.h b/Engine/source/BadBehavior/core/Core.h new file mode 100644 index 000000000..ae18b1909 --- /dev/null +++ b/Engine/source/BadBehavior/core/Core.h @@ -0,0 +1,151 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BBCORE_H_ +#define _BBCORE_H_ + +#ifndef _SIMSET_H_ +#include "console/simSet.h" +#endif +#ifndef _SIMOBJECT_H_ +#include "console/simObject.h" +#endif + +extern bool gInBtEditor; + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // return status values + //--------------------------------------------------------------------------- + enum Status + { + INVALID = -1, + FAILURE, + SUCCESS, + RUNNING, + SUSPENDED, + RESUME + }; + + class Task; + class BehaviorTreeRunner; + + //--------------------------------------------------------------------------- + // node base class + // derived from SimGroup for easy editor integration + //--------------------------------------------------------------------------- + class Node : public SimGroup + { + typedef SimGroup Parent; + + public: + // create a runtime task for this node + virtual Task* createTask(SimObject &owner, BehaviorTreeRunner &runner) = 0; + }; + + //--------------------------------------------------------------------------- + // Leaf node base class - for nodes without children + //--------------------------------------------------------------------------- + class LeafNode : public Node + { + typedef Node Parent; + + public: + virtual void addObject(SimObject *obj); + virtual bool acceptsAsChild( SimObject *object ) const; + }; + + + //--------------------------------------------------------------------------- + // base class for all behavior tree tasks + //--------------------------------------------------------------------------- + class Task + { + protected: + + // the current status + Status mStatus; + + // has the task finished + bool mIsComplete; + + // the node associated with this task + Node *mNodeRep; + + // the object that owns us + SimObjectPtr mOwner; + + // the object running us + BehaviorTreeRunner *mRunner; + + // the parent of this task + Task *mParent; + + // update + virtual Task* update() = 0; + + // initialize + virtual void onInitialize(); + + // terminate + virtual void onTerminate(); + + public: + // tasks are instantiated with a reference to their associated node + Task(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~Task(); + + // status sets and gets + virtual Status getStatus(); + void setStatus(Status newStatus); + + // parent sets and gets + void setParent(Task *parent); + Task *getParent(); + + // run the task + Task* tick(); + + // called when child task finishes + virtual void onChildComplete(Status); + + // called when a suspended task becomes active + virtual void onResume(); + + // prepare the task + void setup(); + + // finish the task + void finish(); + + // reset the task + void reset(); + }; + +} // namespace BadBehavior + +// make the return status enum accessible from script +typedef BadBehavior::Status BehaviorReturnType; +DefineEnumType( BehaviorReturnType ); + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Decorator.cpp b/Engine/source/BadBehavior/core/Decorator.cpp new file mode 100644 index 000000000..146e72ffd --- /dev/null +++ b/Engine/source/BadBehavior/core/Decorator.cpp @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Decorator.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Base decorator node +// overrides for decorators to only allow 1 child +//------------------------------------------------------------------------------ +void DecoratorNode::addObject(SimObject *obj) +{ + if(empty()) + Parent::addObject(obj); +} + +bool DecoratorNode::acceptsAsChild( SimObject *object ) const +{ + return (dynamic_cast(object) && empty()); +} + +//------------------------------------------------------------------------------ +// Base decorator task +//------------------------------------------------------------------------------ +DecoratorTask::DecoratorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mChild(NULL) +{ +} + +DecoratorTask::~DecoratorTask() +{ + if(mChild) + { + delete mChild; + mChild = NULL; + } +} + +void DecoratorTask::onInitialize() +{ + if(!mChild) + { + if(mNodeRep->size() > 0) + { + Node *childNode = static_cast(*mNodeRep->begin()); + if(childNode) + { + mChild = childNode->createTask(*mOwner, *mRunner); + if(mChild) + { + mChild->setParent(this); + mChild->reset(); + } + } + } + } + + mStatus = INVALID; +} + +void DecoratorTask::onTerminate() +{ + mStatus = INVALID; +} + +Task* DecoratorTask::update() +{ + // first time through, return child + if(!mIsComplete) + return mStatus != SUSPENDED ? mChild : NULL; + + // child has completed, are we latent? + if(mStatus == RUNNING || mStatus == SUSPENDED) + mIsComplete = false; + + // no more children + return NULL; +} + +void DecoratorTask::onChildComplete(Status s) +{ + // set our status to the child status and flag completed + mStatus = s; + mIsComplete = true; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Decorator.h b/Engine/source/BadBehavior/core/Decorator.h new file mode 100644 index 000000000..8aa4c7036 --- /dev/null +++ b/Engine/source/BadBehavior/core/Decorator.h @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_DECORATOR_H_ +#define _BB_DECORATOR_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Decorator node base class + //--------------------------------------------------------------------------- + class DecoratorNode : public Node + { + typedef Node Parent; + + public: + // only allow 1 child node to be added + virtual void addObject(SimObject *obj); + virtual bool acceptsAsChild( SimObject *object ) const; + }; + + //--------------------------------------------------------------------------- + // Decorator task base class + //--------------------------------------------------------------------------- + class DecoratorTask : public Task + { + typedef Task Parent; + + protected: + Task* mChild; + + virtual Task* update(); + virtual void onInitialize(); + virtual void onTerminate(); + + public: + DecoratorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~DecoratorTask(); + + virtual void onChildComplete(Status s); + }; + +} // namespace BadBehavior + +#endif diff --git a/Engine/source/BadBehavior/core/Runner.cpp b/Engine/source/BadBehavior/core/Runner.cpp new file mode 100644 index 000000000..9c7d130dd --- /dev/null +++ b/Engine/source/BadBehavior/core/Runner.cpp @@ -0,0 +1,278 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Runner.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +using namespace BadBehavior; + +IMPLEMENT_CONOBJECT(BehaviorTreeRunner); + +BehaviorTreeRunner::BehaviorTreeRunner() + : mOwner(NULL), + mRootNode(NULL), + mRootTask(NULL), + mIsRunning(0), + mTickEvent(0), + mTickFrequency(100) +{} + + +BehaviorTreeRunner::~BehaviorTreeRunner() +{ + delete mRootTask; + + if(Sim::isEventPending(mTickEvent)) + { + Sim::cancelEvent(mTickEvent); + mTickEvent = 0; + } +} + + +void BehaviorTreeRunner::initPersistFields() +{ + addGroup( "Behavior" ); + + addProtectedField("rootNode", TYPEID< SimObject >(), Offset(mRootNode, BehaviorTreeRunner), + &_setRootNode, &defaultProtectedGetFn, "@brief The root node of the tree to be run."); + + addProtectedField("ownerObject", TYPEID< SimObject >(), Offset(mOwner, BehaviorTreeRunner), + &_setOwner, &defaultProtectedGetFn, "@brief The object that owns the tree to be run."); + + addField("frequency", TypeS32, Offset(mTickFrequency, BehaviorTreeRunner), + "@brief The frequency in ms that the tree is ticked at."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +void BehaviorTreeRunner::onDeleteNotify(SimObject *object) +{ + // delete ourselves nicely + // - this takes care of any events registered to this runner + if(object == mOwner.getObject()) + safeDeleteObject(); +} + + +// processTick is where the magic happens :) +void BehaviorTreeRunner::onTick() +{ + PROFILE_SCOPE(BehaviorTreeRunner_processTick); + + // check that we are setup to run + if(mOwner.isNull() || mRootNode.isNull()) + return; + + if(gInBtEditor) + { + if(mRootTask) + reset(); + } + else + { + if(!mRootTask) + { + if((mRootTask = mRootNode->createTask(*mOwner, *this)) == NULL) + { + Con::errorf("BehaviorTreeTicker::processTick, no task for root node"); + return; + } + } + + // dispatch any signals + mSignalHandler.dispatchSignals(); + + // Evaluate the tree + mRootTask->setup(); + mRootTask->tick(); + //Con::warnf("Tree returned %s", EngineMarshallData(mRootTask->getStatus())); + mRootTask->finish(); + } + + // schedule the next tick + if(Sim::isEventPending(mTickEvent)) + Sim::cancelEvent(mTickEvent); + + mTickEvent = Sim::postEvent(this, new BehaviorTreeTickEvent(), Sim::getCurrentTime() + mTickFrequency); + + mIsRunning = true; +} + +void BehaviorTreeRunner::onReactivateEvent(Task *task) +{ + if(task) + task->onResume(); +} + +bool BehaviorTreeRunner::_setRootNode( void *object, const char *index, const char *data ) +{ + BehaviorTreeRunner *runner = static_cast( object ); + Node* root = NULL; + Sim::findObject( data, root ); + if(root) + runner->setRootNode(root); + return false; +} + +bool BehaviorTreeRunner::_setOwner( void *object, const char *index, const char *data ) +{ + BehaviorTreeRunner *runner = static_cast( object ); + SimObject* owner = NULL; + Sim::findObject( data, owner ); + if(owner) + runner->setOwner(owner); + return false; +} + +void BehaviorTreeRunner::setOwner(SimObject *owner) +{ + reset(); + mOwner = owner; + deleteNotify(mOwner); + start(); +} + + +void BehaviorTreeRunner::setRootNode(Node *root) +{ + reset(); + mRootNode = root; + start(); +} + + +void BehaviorTreeRunner::stop() +{ + if(Sim::isEventPending(mTickEvent)) + { + Sim::cancelEvent(mTickEvent); + mTickEvent = 0; + } + mIsRunning = false; +} + + +void BehaviorTreeRunner::start() +{ + if(Sim::isEventPending(mTickEvent)) + { + Sim::cancelEvent(mTickEvent); + mTickEvent = 0; + } + + mIsRunning = true; + if(mRootTask) + mRootTask->reset(); + + mTickEvent = Sim::postEvent(this, new BehaviorTreeTickEvent(), -1); +} + + +void BehaviorTreeRunner::reset() +{ + //stop(); + if(mRootTask) + { + delete mRootTask; + mRootTask = 0; + } + mSignalHandler.reset(); +} + + +void BehaviorTreeRunner::clear() +{ + reset(); + mRootNode = 0; +} + + +bool BehaviorTreeRunner::isRunning() +{ + return mIsRunning; +} + + +void BehaviorTreeRunner::subscribeToSignal(const char *signal, SignalSubscriber *subscriber) +{ + mSignalHandler.registerSubscriber(signal, subscriber); +} + + +void BehaviorTreeRunner::unsubscribeFromSignal(const char *signal, SignalSubscriber *subscriber) +{ + mSignalHandler.unregisterSubscriber(signal, subscriber); +} + + +void BehaviorTreeRunner::postSignal(const char *signal) +{ + mSignalHandler.postSignal(signal); +} + + +DefineEngineMethod( BehaviorTreeRunner, stop, void, (), , + "Halt the execution of the behavior tree.\n\n" + "@note The internal task status is retained, allowing execution to be resumed.") +{ + object->stop(); +} + + +DefineEngineMethod( BehaviorTreeRunner, start, void, (), , + "Resume execution of the (stopped) behavior tree.") +{ + object->start(); +} + + +DefineEngineMethod( BehaviorTreeRunner, reset, void, (), , + "Reset the behavior tree. Any internal state is lost.") +{ + object->reset(); +} + + +DefineEngineMethod( BehaviorTreeRunner, clear, void, (), , + "Clear the behavior tree.") +{ + object->clear(); +} + + +DefineEngineMethod( BehaviorTreeRunner, isRunning, bool, (), , + "Is the behavior tree running") +{ + return object->isRunning(); +} + + +DefineEngineMethod(BehaviorTreeRunner, postSignal, void, (const char *signal),, + "@brief Posts a signal to the behavior tree.\n\n") +{ + object->postSignal( signal ); +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Runner.h b/Engine/source/BadBehavior/core/Runner.h new file mode 100644 index 000000000..ab601089b --- /dev/null +++ b/Engine/source/BadBehavior/core/Runner.h @@ -0,0 +1,140 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_RUNNER_H_ +#define _BB_RUNNER_H_ + +#ifndef _BB_CORE_H_ +#include "Core.h" +#endif +#ifndef _BB_SIGNAL_H_ +#include "Signal.h" +#endif +#ifndef _SIMOBJECT_H_ +#include "console/simObject.h" +#endif +#ifndef _SIMBASE_H_ +#include "console/simBase.h" +#endif +#ifndef _TVECTOR_H_ +#include "util/tVector.h" +#endif + +namespace BadBehavior +{ + + //--------------------------------------------------------------------------- + // BehaviorTreeRunner - handles the evaluation of the tree + //--------------------------------------------------------------------------- + class BehaviorTreeRunner : public SimObject + { + typedef SimObject Parent; + + private: + // is this tree running? + bool mIsRunning; + + // event ID of the tick event + U32 mTickEvent; + + // frequency of ticks in ms + U32 mTickFrequency; + + // the root node of the tree + SimObjectPtr mRootNode; + + // the task associated with the root node + Task *mRootTask; + + // the game object that is using this tree + SimObjectPtr mOwner; + + // signal handler for throwing signals around + SignalHandler mSignalHandler; + + // setters for the script interface + static bool _setRootNode( void *object, const char *index, const char *data ); + static bool _setOwner( void *object, const char *index, const char *data ); + + public: + /*Ctor*/ BehaviorTreeRunner(); + /*Dtor*/ ~BehaviorTreeRunner(); + + // public setters for the script interface + void setOwner(SimObject *owner); + void setRootNode(Node *root); + + // notification if our owner is deleted + virtual void onDeleteNotify(SimObject *object); + + // for script control + void stop(); + void start(); + void reset(); + void clear(); + bool isRunning(); + + // tick + void onTick(); + + // signal handling + void subscribeToSignal(const char *signal, SignalSubscriber *subscriber); + void unsubscribeFromSignal(const char *signal, SignalSubscriber *subscriber); + void postSignal(const char *signal); + + // task reactivation + void onReactivateEvent(Task *task); + + // script interface + static void initPersistFields(); + + DECLARE_CONOBJECT(BehaviorTreeRunner); + }; + + + class BehaviorTreeTickEvent : public SimEvent + { + public: + void process( SimObject *object ) + { + ((BehaviorTreeRunner*)object)->onTick(); + } + }; + + class TaskReactivateEvent : public SimEvent + { + Task *mTask; + public: + TaskReactivateEvent(Task &task) + { + mTask = &task; + } + + void process( SimObject *object ) + { + ((BehaviorTreeRunner*)object)->onReactivateEvent(mTask); + } + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Signal.cpp b/Engine/source/BadBehavior/core/Signal.cpp new file mode 100644 index 000000000..1213fd7ea --- /dev/null +++ b/Engine/source/BadBehavior/core/Signal.cpp @@ -0,0 +1,168 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Signal.h" + +#include "core/stringTable.h" + +using namespace BadBehavior; + +// clean up +SignalHandler::~SignalHandler() +{ + clearSignalQueue(); + clearSubscribers(); +} + +void SignalHandler::clearSignalQueue() +{ + while(!mSignalQueue.empty()) + { + Signal *sig = mSignalQueue.back(); + mSignalQueue.pop_back(); + delete sig; + sig = NULL; + } +} + +void SignalHandler::clearSubscribers() +{ + for( Vector::const_iterator it = mSignals.begin(); it != mSignals.end(); ++it ) + { + // Delete the subscriber list. + VectorPtr* subscribers = mSubscribers.remove( *it ); + if(subscribers) + delete subscribers; + } +} + +void SignalHandler::reset() +{ + // empty out the signal queue + clearSignalQueue(); + + // clear out the subscribers table + clearSubscribers(); + + // reset the vector of registered signals + mSignals.clear(); +} + +// check if the specified signal is registered +bool SignalHandler::isSignalRegistered(const char *signal) +{ + StringTableEntry signalName = StringTable->insert( signal ); + return mSignals.contains(signalName); +} + +// register a signal +void SignalHandler::registerSignal(const char *signal) +{ + // check signal has a name + if(!signal || !signal[0]) + return; + + // Make sure the signal has not been registered yet. + if(!isSignalRegistered( signal ) ) + { + // Add to the signal list. + mSignals.push_back( StringTable->insert( signal ) ); + + // Create a list of subscribers for this event. + mSubscribers.insert( new VectorPtr, signal ); + } +} + +// register a subscriber to a signal +void SignalHandler::registerSubscriber(const char *signal, SignalSubscriber *subscriber) +{ + // must have a subscriber + if(!subscriber) + return; + + // and an signal name + if(!signal || !signal[0]) + return; + + // register a new event if this one hasn't already been registered + if(!isSignalRegistered(signal)) + registerSignal(signal); + + // add the subscriber if it's not already registered for this signal + VectorPtr* subscribers = mSubscribers.retreive( signal ); + + if(!subscribers->contains(subscriber)) + subscribers->push_back(subscriber); +} + +// unregister a subscriber +void SignalHandler::unregisterSubscriber(const char *signal, SignalSubscriber *subscriber) +{ + // check if the subscriber exists and that the signal is actually registered + if(!subscriber || !isSignalRegistered(signal)) + return; + + // find the subscriber and remove it + VectorPtr* subscribers = mSubscribers.retreive( signal ); + + for( VectorPtr::iterator iter = subscribers->begin(); iter != subscribers->end(); ++iter ) + { + if( *iter == subscriber ) + { + subscribers->erase_fast( iter ); + break; + } + } +} + +// post a signal +void SignalHandler::postSignal(const char *signal) +{ + // signal must be registered + if(!isSignalRegistered(signal)) + return; + + // dispatch a signal to each of the subscribers + VectorPtr* subscribers = mSubscribers.retreive( signal ); + + for( VectorPtr::iterator iter = subscribers->begin(); iter != subscribers->end(); ++iter ) + { + mSignalQueue.push_back(new Signal((*iter))); + } +} + + +// dispatch queued signals +void SignalHandler::dispatchSignals() +{ + if(mSignalQueue.empty()) + return; + + while(!mSignalQueue.empty()) + { + Signal *sig = mSignalQueue.back(); + mSignalQueue.pop_back(); + sig->send(); + delete sig; + sig = NULL; + } +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Signal.h b/Engine/source/BadBehavior/core/Signal.h new file mode 100644 index 000000000..e1285f3a9 --- /dev/null +++ b/Engine/source/BadBehavior/core/Signal.h @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SIGNAL_H_ +#define _BB_SIGNAL_H_ + +#ifndef _TVECTOR_H_ +#include "core/util/tVector.h" +#endif +#ifndef _TSIMPLEHASHTABLE_H +#include "core/tSimpleHashTable.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Signal subscriber interface + //--------------------------------------------------------------------------- + class SignalSubscriber + { + protected: + virtual void subscribe() = 0; + virtual void unsubscribe() = 0; + + public: + virtual void onSignal() = 0; + }; + + //--------------------------------------------------------------------------- + // Signal class + //--------------------------------------------------------------------------- + class Signal + { + private: + SignalSubscriber *mSubscriber; + public: + Signal(SignalSubscriber *subscriber) : mSubscriber(subscriber) {} + void send() { if(mSubscriber) mSubscriber->onSignal(); } + }; + + //--------------------------------------------------------------------------- + // SignalHandler + // Simple handler to pass signals to tree task listeners + //--------------------------------------------------------------------------- + class SignalHandler + { + private: + SimpleHashTable > mSubscribers; + Vector mSignals; + + VectorPtr mSignalQueue; + + void registerSignal(const char *signal); + bool isSignalRegistered(const char *signal); + void clearSignalQueue(); + void clearSubscribers(); + + public: + SignalHandler() {} + ~SignalHandler(); + + // reset + void reset(); + + // register a scubscriber + void registerSubscriber(const char *signal, SignalSubscriber *subscriber); + + // unregister a subscriber + void unregisterSubscriber(const char *signal, SignalSubscriber *subscriber); + + // post an signal + void postSignal(const char *signal); + + // dispatch queued signals + void dispatchSignals(); + }; +} // namespace BadBehavior +#endif diff --git a/Engine/source/BadBehavior/core/Stepper.cpp b/Engine/source/BadBehavior/core/Stepper.cpp new file mode 100644 index 000000000..f919681be --- /dev/null +++ b/Engine/source/BadBehavior/core/Stepper.cpp @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Stepper.h" + +using namespace BadBehavior; + +Status BehaviorTreeStepper::stepThrough(VectorPtr &taskVector) +{ + if(taskVector.empty()) return INVALID; + + if(taskVector.back()->getStatus() == SUSPENDED) + return SUSPENDED; + + Status status = INVALID; + + // loop through the tasks in the task list + while(!taskVector.empty()) + { + // get a task + Task *currentTask = taskVector.back(); + + // tick the task + Task *nextTask = currentTask->tick(); + + // if task returned no children, it has completed + if(!nextTask) + { + // stop if it's RUNNING or SUSPENED + status = currentTask->getStatus(); + if(status == RUNNING || status == SUSPENDED) + break; + + // otherwise, remove it from the list + taskVector.pop_back(); + if(!taskVector.empty()) + // and tell its parent that it completed + taskVector.back()->onChildComplete(currentTask->getStatus()); + + // complete the task + currentTask->finish(); + } + else + { + // add the child as a task + nextTask->setup(); + taskVector.push_back(nextTask); + } + } + + return status; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/Stepper.h b/Engine/source/BadBehavior/core/Stepper.h new file mode 100644 index 000000000..78d2df5be --- /dev/null +++ b/Engine/source/BadBehavior/core/Stepper.h @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_STEPPER_H_ +#define _BB_STEPPER_H_ + +#ifndef _BB_CORE_H_ +#include "Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // helper class for stepping through a tree + //--------------------------------------------------------------------------- + class BehaviorTreeStepper + { + public: + static Status stepThrough(VectorPtr &taskVector); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/core/behavior.cpp b/Engine/source/BadBehavior/core/behavior.cpp new file mode 100644 index 000000000..94a0f20e0 --- /dev/null +++ b/Engine/source/BadBehavior/core/behavior.cpp @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "behavior.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// script enum for precondition mode +//------------------------------------------------------------------------------ +ImplementEnumType( BehaviorPreconditionType, + "@brief When should the precondition function be evaluated.\n\n" + "@ingroup AI\n\n") + { ONCE, "ONCE", "The first time the node is executed.\n" }, + { TICK, "TICK", "Each time the node is executed.\n" }, +EndImplementEnumType; + +//------------------------------------------------------------------------------ +// Behavior node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Behavior); + +Behavior::Behavior() + : mPreconditionMode(ONCE) +{ +} + +void Behavior::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "preconditionMode", TYPEID< BadBehavior::PreconditionMode >(), Offset(mPreconditionMode, Behavior), + "@brief When to evaluate the precondition function."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *Behavior::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new BehaviorTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// ScriptedBehavior task +//------------------------------------------------------------------------------ +BehaviorTask::BehaviorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +Task* BehaviorTask::update() +{ + PROFILE_SCOPE(BehaviorTask_update); + + Behavior *node = static_cast(mNodeRep); + + // first check preconditions are valid + bool precondition = true; + if( (node->getPreconditionMode() == ONCE && mStatus == INVALID) || (node->getPreconditionMode() == TICK) ) + precondition = node->precondition( mOwner ); + + if(precondition) + { + // run onEnter if this is the first time the node is ticked + if(mStatus == INVALID) + node->onEnter(mOwner); + + // execute the main behavior and get its return value + mStatus = node->behavior(mOwner); + } + else + { + mStatus = FAILURE; + } + + mIsComplete = mStatus != RUNNING && mStatus != SUSPENDED; + + if(mIsComplete) + node->onExit(mOwner); + + return NULL; // leaves don't have children +} diff --git a/Engine/source/BadBehavior/core/behavior.h b/Engine/source/BadBehavior/core/behavior.h new file mode 100644 index 000000000..cdc8e9482 --- /dev/null +++ b/Engine/source/BadBehavior/core/behavior.h @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_BEHAVIOR_H_ +#define _BB_BEHAVIOR_H_ + +#ifndef _BB_CORE_H_ +#include "Core.h" +#endif + +namespace BadBehavior +{ + // specify when the precondition function should be executed + enum PreconditionMode + { + ONCE, // the first time the behavior is evaluated + TICK // every tick + }; + + //--------------------------------------------------------------------------- + // Behavior - Base class for structured behavior leaf nodes + //--------------------------------------------------------------------------- + class Behavior : public LeafNode + { + typedef LeafNode Parent; + + protected: + // how often should we valuate the precondition + PreconditionMode mPreconditionMode; + + public: + Behavior(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + const PreconditionMode &getPreconditionMode() const { return mPreconditionMode; } + + virtual bool precondition( SimObject *owner ) { return true; } + virtual void onEnter( SimObject *owner ) {} + virtual void onExit( SimObject *owner ) {} + virtual Status behavior( SimObject *owner ) { return SUCCESS; } + + DECLARE_CONOBJECT(Behavior); + }; + + //--------------------------------------------------------------------------- + // Behavior task + //--------------------------------------------------------------------------- + class BehaviorTask : public Task + { + typedef Task Parent; + + protected: + virtual Task* update(); + + public: + BehaviorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + }; + +} // namespace BadBehavior + +// make the return precondition mode accessible from script +typedef BadBehavior::PreconditionMode BehaviorPreconditionType; +DefineEnumType( BehaviorPreconditionType ); + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/FailAlways.cpp b/Engine/source/BadBehavior/decorator/FailAlways.cpp new file mode 100644 index 000000000..49c2d0852 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/FailAlways.cpp @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "FailAlways.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// FailAlways decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(FailAlways); + +Task *FailAlways::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new FailAlwaysTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// FailAlways decorator task +//------------------------------------------------------------------------------ +FailAlwaysTask::FailAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void FailAlwaysTask::onChildComplete(Status s) +{ + Parent::onChildComplete(s); + if(mStatus == SUCCESS) + mStatus = FAILURE; +} + diff --git a/Engine/source/BadBehavior/decorator/FailAlways.h b/Engine/source/BadBehavior/decorator/FailAlways.h new file mode 100644 index 000000000..65ba3766c --- /dev/null +++ b/Engine/source/BadBehavior/decorator/FailAlways.h @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_FAILALWAYS_H_ +#define _BB_FAILALWAYS_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // FailAlways decorator + // Returns FAILURE if child returns SUCCESS or FAILURE. RUNNING and INVALID are unchanged + //--------------------------------------------------------------------------- + class FailAlways : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(FailAlways); + }; + + //--------------------------------------------------------------------------- + // FailAlways task + //--------------------------------------------------------------------------- + class FailAlwaysTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + public: + FailAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status s); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Inverter.cpp b/Engine/source/BadBehavior/decorator/Inverter.cpp new file mode 100644 index 000000000..0defd9ab7 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Inverter.cpp @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Inverter.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Inverter decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Inverter); + +Task *Inverter::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new InverterTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Inverter decorator task +//------------------------------------------------------------------------------ +InverterTask::InverterTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void InverterTask::onChildComplete(Status s) +{ + Parent::onChildComplete(s); + + // invert SUCCESS or FAILURE, leave INVALID and RUNNING unchanged + if (mStatus == SUCCESS) + mStatus = FAILURE; + else if (mStatus == FAILURE) + mStatus = SUCCESS; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Inverter.h b/Engine/source/BadBehavior/decorator/Inverter.h new file mode 100644 index 000000000..0cc38537e --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Inverter.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_INVERTER_H_ +#define _BB_INVERTER_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // inverter decorator + // invert the return value of the child, + // SUCCESS becomes FAILURE, FAILURE becomes SUCCESS, INVALID and RUNNING are unmodified + //--------------------------------------------------------------------------- + class Inverter : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(Inverter); + }; + + //--------------------------------------------------------------------------- + // inverter decorator task + //--------------------------------------------------------------------------- + class InverterTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + public: + InverterTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status s); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Loop.cpp b/Engine/source/BadBehavior/decorator/Loop.cpp new file mode 100644 index 000000000..46ee12606 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Loop.cpp @@ -0,0 +1,120 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Loop.h" + +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Loop decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Loop); + +ImplementEnumType( LoopTerminationPolicy, + "@brief The policy to use when determining if the loop should terminate early.\n\n" + "@ingroup AI\n\n") + { Loop::ON_FAILURE, "ON_FAILURE", "Will terminate and return FAILURE if child fails.\n" }, + { Loop::ON_SUCCESS, "ON_SUCCESS", "Will terminate and return SUCCESS if child succeeds.\n" }, +EndImplementEnumType; + +Loop::Loop() + : mNumLoops(0), + mTerminationPolicy(ON_FAILURE) +{ +} + +void Loop::initPersistFields() +{ + addGroup( "Behavior" ); + + addProtectedField( "numLoops", TypeS32, Offset(mNumLoops, Loop), &_setNumLoops, &defaultProtectedGetFn, + "The number of times to repeat the child behavior. 0 = infinite." ); + + addField( "terminationPolicy", TYPEID< Loop::TerminationPolicy >(), Offset(mTerminationPolicy, Loop), + "@brief The policy to use when deciding if the loop should terminate before completion."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +bool Loop::_setNumLoops(void *object, const char *index, const char *data) +{ + Loop *node = static_cast( object ); + node->mNumLoops = getMax(0, dAtoi( data )); + return false; +} + +Task *Loop::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new LoopTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Loop decorator task +//------------------------------------------------------------------------------ +LoopTask::LoopTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mCurrentLoop(0) +{ +} + +void LoopTask::onInitialize() +{ + Parent::onInitialize(); + mCurrentLoop = 0; +} + +Task* LoopTask::update() +{ + if(Parent::update()) + return mChild; + + if(mStatus == RUNNING || mStatus == SUSPENDED) + mIsComplete = false; + + // child has terminated with SUCCESS or FAILURE + if( mIsComplete ) + { + // check if we should continue looping or reset + Loop *nodeRep = static_cast(mNodeRep); + Loop::TerminationPolicy policy = nodeRep->getTerminationPolicy(); + S32 numLoops = nodeRep->getNumLoops(); + + // termination policy not met? + if( ((policy == Loop::ON_FAILURE) && (mStatus != FAILURE)) || + ((policy == Loop::ON_SUCCESS) && (mStatus != SUCCESS)) ) + { + // more looping to be done + if ( (++mCurrentLoop < numLoops) || (numLoops == 0) ) + { + mIsComplete = false; + mStatus = RUNNING; + } + } + } + + // no children to return + return NULL; +} diff --git a/Engine/source/BadBehavior/decorator/Loop.h b/Engine/source/BadBehavior/decorator/Loop.h new file mode 100644 index 000000000..2b5deb5be --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Loop.h @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_LOOP_H_ +#define _BB_LOOP_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // loop decorator + // repeats the child behaviour for n times, or until it fails + // returns RUNNING until it completes + //--------------------------------------------------------------------------- + class Loop : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + // loop termination policies + enum TerminationPolicy + { + ON_FAILURE, + ON_SUCCESS, + }; + + protected: + static bool _setNumLoops(void *object, const char *index, const char *data); + S32 mNumLoops; + TerminationPolicy mTerminationPolicy; + + public: + Loop(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + S32 getNumLoops() const { return mNumLoops; } + TerminationPolicy getTerminationPolicy() const { return mTerminationPolicy; } + + DECLARE_CONOBJECT(Loop); + }; + + //--------------------------------------------------------------------------- + // loop task + //--------------------------------------------------------------------------- + class LoopTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + protected: + S32 mCurrentLoop; + + virtual void onInitialize(); + virtual Task *update(); + + public: + LoopTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + }; + +} // namespace BadBehavior + +// make the loop termination policy enum accessible from script +typedef BadBehavior::Loop::TerminationPolicy LoopTerminationPolicy; +DefineEnumType( LoopTerminationPolicy ); + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Monitor.cpp b/Engine/source/BadBehavior/decorator/Monitor.cpp new file mode 100644 index 000000000..fc434c9e2 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Monitor.cpp @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Monitor.h" + +#include "console/engineAPI.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Monitor decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Monitor); + +Task *Monitor::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new MonitorTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Logger decorator task +//------------------------------------------------------------------------------ +MonitorTask::MonitorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void MonitorTask::onChildComplete(Status s) +{ + Parent::onChildComplete(s); + + Con::printf("%s (%s) child returning %s", static_cast(mNodeRep)->getInternalName(), + static_cast(mNodeRep)->getIdString(), + EngineMarshallData< BehaviorReturnType > (mStatus)); +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Monitor.h b/Engine/source/BadBehavior/decorator/Monitor.h new file mode 100644 index 000000000..2fbd707ba --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Monitor.h @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_MONITOR_H_ +#define _BB_MONITOR_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Monitor decorator + // outputs the return status to the console, + //--------------------------------------------------------------------------- + class Monitor : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(Monitor); + }; + + //--------------------------------------------------------------------------- + // Monitor decorator task + //--------------------------------------------------------------------------- + class MonitorTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + public: + MonitorTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status s); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Root.cpp b/Engine/source/BadBehavior/decorator/Root.cpp new file mode 100644 index 000000000..42f10a5dc --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Root.cpp @@ -0,0 +1,75 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Root.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Root decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Root); + +Task *Root::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new RootTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Root decorator task +//------------------------------------------------------------------------------ +RootTask::RootTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mBranch(NULL) +{ +} + +RootTask::~RootTask() +{ + if(mBranch) + delete mBranch; +} + +void RootTask::onInitialize() +{ + Parent::onInitialize(); + if(!mBranch) + mBranch = new BehaviorTreeBranch(mChild); + else + mBranch->reset(); +} + +Task *RootTask::update() +{ + mStatus = mBranch->update(); + + mIsComplete = mStatus != RUNNING && mStatus != SUSPENDED; + return NULL; +} + +Status RootTask::getStatus() +{ + if(mStatus == SUSPENDED) + return mBranch->getStatus(); + + return mStatus; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Root.h b/Engine/source/BadBehavior/decorator/Root.h new file mode 100644 index 000000000..4b9a97115 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Root.h @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_ROOT_H_ +#define _BB_ROOT_H_ + +#ifndef _BB_BRANCH_H_ +#include "BadBehavior/core/Branch.h" +#endif +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Root decorator + // A placeholder node to mark the start of a tree. + // Used by the editor, bypassed during tree evaluation. + //--------------------------------------------------------------------------- + class Root : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + virtual Task* createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(Root); + }; + + //--------------------------------------------------------------------------- + // Root task + //--------------------------------------------------------------------------- + class RootTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + protected: + BehaviorTreeBranch *mBranch; + + virtual Task* update(); + virtual void onInitialize(); + //virtual void onTerminate(); + + public: + RootTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~RootTask(); + + virtual Status getStatus(); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/SucceedAlways.cpp b/Engine/source/BadBehavior/decorator/SucceedAlways.cpp new file mode 100644 index 000000000..fb6846234 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/SucceedAlways.cpp @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "SucceedAlways.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// SucceedAlways decorator node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(SucceedAlways); + +Task *SucceedAlways::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new SucceedAlwaysTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// SucceedAlways decorator task +//------------------------------------------------------------------------------ +SucceedAlwaysTask::SucceedAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +void SucceedAlwaysTask::onChildComplete(Status s) +{ + Parent::onChildComplete(s); + if(mStatus == FAILURE) + mStatus = SUCCESS; +} + diff --git a/Engine/source/BadBehavior/decorator/SucceedAlways.h b/Engine/source/BadBehavior/decorator/SucceedAlways.h new file mode 100644 index 000000000..cdb1c0204 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/SucceedAlways.h @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SUCCEEDALWAYS_H_ +#define _BB_SUCCEEDALWAYS_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // SucceedAlways decorator + // Returns SUCCESS if child returns SUCCESS or FAILURE. RUNNING and INVALID are unchanged + //--------------------------------------------------------------------------- + class SucceedAlways : public DecoratorNode + { + typedef DecoratorNode Parent; + + public: + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + DECLARE_CONOBJECT(SucceedAlways); + }; + + //--------------------------------------------------------------------------- + // SucceedAlways task + //--------------------------------------------------------------------------- + class SucceedAlwaysTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + public: + SucceedAlwaysTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + + virtual void onChildComplete(Status s); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Ticker.cpp b/Engine/source/BadBehavior/decorator/Ticker.cpp new file mode 100644 index 000000000..d1929ad33 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Ticker.cpp @@ -0,0 +1,136 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "Ticker.h" +#include "BadBehavior/core/Runner.h" + +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Ticker decorator node +// **** EXPERIMENTAL **** +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Ticker); + +Ticker::Ticker() + : mFrequencyMs(100) +{ +} + +void Ticker::initPersistFields() +{ + addGroup( "Behavior" ); + + addProtectedField( "frequencyMs", TypeS32, Offset(mFrequencyMs, Ticker), &_setFrequency, &defaultProtectedGetFn, + "The time to wait between evaluations of this nodes child." ); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +bool Ticker::_setFrequency(void *object, const char *index, const char *data) +{ + Ticker *node = static_cast( object ); + node->mFrequencyMs = getMax(0, dAtoi( data )); + return false; +} + +Task *Ticker::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new TickerTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Ticker decorator task +//------------------------------------------------------------------------------ +TickerTask::TickerTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mNextTimeMs(0), + mEventId(0), + mBranch(NULL) +{ +} + +TickerTask::~TickerTask() +{ + cancelEvent(); + + if(mBranch) + delete mBranch; +} + +void TickerTask::cancelEvent() +{ + if(Sim::isEventPending(mEventId)) + { + Sim::cancelEvent(mEventId); + mEventId = 0; + } +} + +void TickerTask::onInitialize() +{ + Parent::onInitialize(); + cancelEvent(); + if(!mBranch) + mBranch = new BehaviorTreeBranch(mChild); + else + mBranch->reset(); +} + +void TickerTask::onTerminate() +{ + Parent::onTerminate(); + cancelEvent(); +} + +Task* TickerTask::update() +{ + if(Sim::getCurrentTime() < mNextTimeMs) + { + if(!Sim::isEventPending(mEventId)) + mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), mNextTimeMs); + + mStatus = SUSPENDED; + } + else if(mStatus != SUSPENDED) + { + mNextTimeMs = Sim::getCurrentTime() + static_cast(mNodeRep)->getFrequencyMs(); + Status s = mBranch->update(); + mStatus = s != SUSPENDED ? s : RUNNING; + } + + mIsComplete = mStatus != SUSPENDED && mStatus != RUNNING; + + return NULL; +} + +Status TickerTask::getStatus() +{ + if(mStatus != SUSPENDED && mStatus != RESUME) + return mBranch->getStatus(); + + return mStatus; +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/decorator/Ticker.h b/Engine/source/BadBehavior/decorator/Ticker.h new file mode 100644 index 000000000..06b96ea07 --- /dev/null +++ b/Engine/source/BadBehavior/decorator/Ticker.h @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_TICKER_H_ +#define _BB_TICKER_H_ + +#ifndef _BB_DECORATOR_H_ +#include "BadBehavior/core/Decorator.h" +#endif +#ifndef _BB_BRANCH_H_ +#include "BadBehavior/core/Branch.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Ticker decorator + // Limits the frequency at which it's children are updated. + //--------------------------------------------------------------------------- + class Ticker : public DecoratorNode + { + typedef DecoratorNode Parent; + + protected: + static bool _setFrequency(void *object, const char *index, const char *data); + + // time between ticks (in ms) + S32 mFrequencyMs; + + public: + Ticker(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + S32 getFrequencyMs() const { return mFrequencyMs; } + + DECLARE_CONOBJECT(Ticker); + }; + + //--------------------------------------------------------------------------- + // Ticker decorator task + //--------------------------------------------------------------------------- + class TickerTask : public DecoratorTask + { + typedef DecoratorTask Parent; + + protected: + U32 mNextTimeMs; + U32 mEventId; + + BehaviorTreeBranch *mBranch; + + virtual void onInitialize(); + virtual void onTerminate(); + virtual Task* update(); + + void cancelEvent(); + + public: + TickerTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~TickerTask(); + + virtual Status getStatus(); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/RandomWait.cpp b/Engine/source/BadBehavior/leaf/RandomWait.cpp new file mode 100644 index 000000000..35a94e1d6 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/RandomWait.cpp @@ -0,0 +1,125 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "RandomWait.h" +#include "BadBehavior/core/Runner.h" + +#include "math/mMathFn.h" +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// RandomWait leaf node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(RandomWait); + +RandomWait::RandomWait() + : mWaitMinMs(0), + mWaitMaxMs(99999) +{ +} + +void RandomWait::initPersistFields() +{ + addGroup( "Behavior" ); + + addProtectedField( "waitMinMs", TypeS32, Offset(mWaitMinMs, RandomWait), &_setWaitMin, &defaultProtectedGetFn, + "The minimum time period in ms to wait before completion." ); + + addProtectedField( "waitMaxMs", TypeS32, Offset(mWaitMaxMs, RandomWait), &_setWaitMax, &defaultProtectedGetFn, + "The maximum time period in ms to wait before completion." ); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +bool RandomWait::_setWaitMin(void *object, const char *index, const char *data) +{ + RandomWait *node = static_cast( object ); + node->mWaitMinMs = getMin(node->mWaitMaxMs, dAtoi( data )); + return false; +} + +bool RandomWait::_setWaitMax(void *object, const char *index, const char *data) +{ + RandomWait *node = static_cast( object ); + node->mWaitMaxMs = getMax(node->mWaitMinMs, dAtoi( data )); + return false; +} + +Task *RandomWait::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new RandomWaitTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// RandomWait task +//------------------------------------------------------------------------------ +RandomWaitTask::RandomWaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +RandomWaitTask::~RandomWaitTask() +{ + cancelEvent(); +} + +void RandomWaitTask::cancelEvent() +{ + if(Sim::isEventPending(mEventId)) + { + Sim::cancelEvent(mEventId); + mEventId = 0; + } +} + +void RandomWaitTask::onInitialize() +{ + Parent::onInitialize(); + cancelEvent(); +} + +void RandomWaitTask::onTerminate() +{ + Parent::onTerminate(); + cancelEvent(); +} + +Task* RandomWaitTask::update() +{ + if(mStatus == RESUME) + { + mStatus = SUCCESS; + mIsComplete = true; + } + else if(mStatus == INVALID) + { + RandomWait *node = static_cast(mNodeRep); + mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), Sim::getCurrentTime() + mRandI(node->getWaitMinMs(), node->getWaitMaxMs())); + mStatus = SUSPENDED; + } + + return NULL; +} diff --git a/Engine/source/BadBehavior/leaf/RandomWait.h b/Engine/source/BadBehavior/leaf/RandomWait.h new file mode 100644 index 000000000..b83e0f4c1 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/RandomWait.h @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_RANDOMWAIT_H_ +#define _BB_RANDOMWAIT_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // RandomWait leaf + // Pauses for a random period of time between delayMin and delayMax ms before completing. + //--------------------------------------------------------------------------- + class RandomWait : public LeafNode + { + typedef LeafNode Parent; + + protected: + static bool _setWaitMin(void *object, const char *index, const char *data); + static bool _setWaitMax(void *object, const char *index, const char *data); + + S32 mWaitMinMs; + S32 mWaitMaxMs; + + public: + RandomWait(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + S32 getWaitMinMs() const { return mWaitMinMs; } + S32 getWaitMaxMs() const { return mWaitMaxMs; } + + DECLARE_CONOBJECT(RandomWait); + }; + + //--------------------------------------------------------------------------- + // RandomWait leaf task + //--------------------------------------------------------------------------- + class RandomWaitTask : public Task + { + typedef Task Parent; + + protected: + U32 mEventId; + + virtual void onInitialize(); + virtual void onTerminate(); + virtual Task* update(); + + void cancelEvent(); + + public: + RandomWaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~RandomWaitTask(); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/ScriptEval.cpp b/Engine/source/BadBehavior/leaf/ScriptEval.cpp new file mode 100644 index 000000000..594910105 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptEval.cpp @@ -0,0 +1,94 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "ScriptEval.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// ScriptEval node - warning, slow! +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(ScriptEval); + +ScriptEval::ScriptEval() + : mDefaultReturnStatus(SUCCESS) +{ +} + +void ScriptEval::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "behaviorScript", TypeCommand, Offset(mBehaviorScript, ScriptEval), + "@brief The command to execute when the leaf is ticked. Max 255 characters." ); + + addField( "defaultReturnStatus", TYPEID< BadBehavior::Status >(), Offset(mDefaultReturnStatus, ScriptEval), + "@brief The default value for this node to return."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *ScriptEval::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new ScriptEvalTask(*this, owner, runner); +} + +Status ScriptEval::evaluateScript( SimObject *owner ) +{ + PROFILE_SCOPE(ScriptEval_evaluateScript); + + if(mBehaviorScript.isEmpty()) + return mDefaultReturnStatus; + + // get the result + const char *result = Con::evaluatef("%%obj=%s; %s return %s;", + owner->getIdString(), + mBehaviorScript.c_str(), + EngineMarshallData< BehaviorReturnType >(mDefaultReturnStatus)); + + if(result[0] == '1' || result[0] == '0') + // map true or false to SUCCEED or FAILURE + return static_cast(dAtoi(result)); + + // convert the returned value to our internal enum type + return EngineUnmarshallData< BehaviorReturnType >()( result ); +} + +//------------------------------------------------------------------------------ +// RunScript task +//------------------------------------------------------------------------------ +ScriptEvalTask::ScriptEvalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +Task* ScriptEvalTask::update() +{ + mStatus = static_cast(mNodeRep)->evaluateScript( mOwner ); + + return NULL; // leaves don't have children +} diff --git a/Engine/source/BadBehavior/leaf/ScriptEval.h b/Engine/source/BadBehavior/leaf/ScriptEval.h new file mode 100644 index 000000000..23be24b18 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptEval.h @@ -0,0 +1,75 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SCRIPTEVAL_H_ +#define _BB_SCRIPTEVAL_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // ScriptEval - evaluates a set of Torque Script commands when run + // Warning - slow, handle with care! + //--------------------------------------------------------------------------- + class ScriptEval : public LeafNode + { + typedef LeafNode Parent; + + private: + // status to return if the command does not return a value + Status mDefaultReturnStatus; + + // the torque script to evaluate + String mBehaviorScript; + + public: + ScriptEval(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + // execute the script + Status evaluateScript(SimObject *owner); + + DECLARE_CONOBJECT(ScriptEval); + }; + + //--------------------------------------------------------------------------- + // ScriptEval task + //--------------------------------------------------------------------------- + class ScriptEvalTask : public Task + { + typedef Task Parent; + + protected: + virtual Task* update(); + + public: + ScriptEvalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + }; + +} // namespace BadBehavior +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/ScriptFunc.cpp b/Engine/source/BadBehavior/leaf/ScriptFunc.cpp new file mode 100644 index 000000000..37b52b244 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptFunc.cpp @@ -0,0 +1,121 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "ScriptFunc.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// ScriptFunc node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(ScriptFunc); + +ScriptFunc::ScriptFunc() + : mDefaultReturnStatus(SUCCESS), + mScriptFunction(StringTable->insert("")) +{ + for(U8 i = 0; i < MAX_COMMAND_ARGS; ++i) + mScriptArgs[i] = StringTable->insert(""); +} + + +void ScriptFunc::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "func", TypeCaseString, Offset(mScriptFunction, ScriptFunc), + "@brief The function to execute when the leaf is ticked." ); + + addField( "args", TypeCaseString, Offset(mScriptArgs, ScriptFunc), MAX_COMMAND_ARGS, + "@brief The arguments to be passed to the function to be executed." ); + + addField( "defaultReturnStatus", TYPEID< BadBehavior::Status >(), Offset(mDefaultReturnStatus, ScriptFunc), + "@brief The default value for this node to return."); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *ScriptFunc::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new ScriptFuncTask(*this, owner, runner); +} + +Status ScriptFunc::evaluate( SimObject *owner ) +{ + PROFILE_SCOPE(ScriptFunc_evaluate); + + if(!owner) + return INVALID; + + if(!mScriptFunction || !mScriptFunction[0]) + return mDefaultReturnStatus; + + S32 argc = 0; + + const char *args[MAX_COMMAND_ARGS + 2]; + args[0] = mScriptFunction; + + while(argc < MAX_COMMAND_ARGS && (mScriptArgs[argc] && mScriptArgs[argc][0])) + { + args[argc + 2] = mScriptArgs[argc]; + ++argc; + } + + argc += 2; + + // get the result + const char *result = Con::execute(owner, argc, args); + + // if function didn't return a result, return our default status + if(!result || !result[0]) + return mDefaultReturnStatus; + + // map true or false to SUCCEED or FAILURE + if(result[0] == '1' || result[0] == '0') + return static_cast(dAtoi(result)); + + // convert the returned value to our internal enum type + return EngineUnmarshallData< BehaviorReturnType >()( result ); +} + +//------------------------------------------------------------------------------ +// ScriptFunc task +//------------------------------------------------------------------------------ +ScriptFuncTask::ScriptFuncTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner) +{ +} + +Task* ScriptFuncTask::update() +{ + mStatus = static_cast(mNodeRep)->evaluate( mOwner ); + + if(mStatus != RUNNING && mStatus != SUSPENDED) + mIsComplete = true; + + return NULL; // leaves don't have children +} diff --git a/Engine/source/BadBehavior/leaf/ScriptFunc.h b/Engine/source/BadBehavior/leaf/ScriptFunc.h new file mode 100644 index 000000000..af264db96 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptFunc.h @@ -0,0 +1,79 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SCRIPTFUNC_H_ +#define _BB_SCRIPTFUNC_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + static const U8 MAX_COMMAND_ARGS = 4; + + //--------------------------------------------------------------------------- + // ScriptFunc - executes a function on the owner object + //--------------------------------------------------------------------------- + class ScriptFunc : public LeafNode + { + typedef LeafNode Parent; + + protected: + // the function to call + StringTableEntry mScriptFunction; + + // the arguments for the function + StringTableEntry mScriptArgs[MAX_COMMAND_ARGS]; + + // status to return if the command does not return a value + Status mDefaultReturnStatus; + + public: + ScriptFunc(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + // execute the command + Status evaluate(SimObject *owner); + + DECLARE_CONOBJECT(ScriptFunc); + }; + + //--------------------------------------------------------------------------- + // ScriptFunc task + //--------------------------------------------------------------------------- + class ScriptFuncTask : public Task + { + typedef Task Parent; + + protected: + virtual Task* update(); + + public: + ScriptFuncTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + }; + +} // namespace BadBehavior +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/ScriptedBehavior.cpp b/Engine/source/BadBehavior/leaf/ScriptedBehavior.cpp new file mode 100644 index 000000000..6140542eb --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptedBehavior.cpp @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "ScriptedBehavior.h" + +#include "console/engineAPI.h" +#include "platform/profiler.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// ScriptedBehavior node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(ScriptedBehavior); + +IMPLEMENT_CALLBACK( ScriptedBehavior, onEnter, void, ( SimObject* owner ), ( owner ), + "Called when the behavior is first run.\n" + "@param owner The object that this behavior tree belongs to." ); + +IMPLEMENT_CALLBACK( ScriptedBehavior, onExit, void, ( SimObject* owner ), ( owner ), + "Called when the behavior is complete.\n" + "@param owner The object that this behavior tree belongs to." ); + +IMPLEMENT_CALLBACK( ScriptedBehavior, precondition, bool, ( SimObject* owner ), ( owner ), + "Called prior to evaluating the behavior.\n" + "@param owner The object that this behavior tree belongs to.\n" + "A return value of false indicates that evaluation of the behavior should stop.\n" + "A return value of true indicates that evaluation of the behavior should continue."); + +IMPLEMENT_CALLBACK( ScriptedBehavior, behavior, Status, ( SimObject* owner ), ( owner ), + "Evaluate the main behavior of this node.\n" + "@param owner The object that this behavior tree belongs to.\n"); + +ScriptedBehavior::ScriptedBehavior() +{ +} + +bool ScriptedBehavior::precondition( SimObject *owner ) +{ + PROFILE_SCOPE( ScriptedBehavior_precondition); + + if(isMethod("precondition")) + return precondition_callback(owner); + + return true; +} + +void ScriptedBehavior::onEnter( SimObject *owner ) +{ + PROFILE_SCOPE( ScriptedBehavior_onEnter ); + onEnter_callback(owner); +} + +void ScriptedBehavior::onExit( SimObject *owner ) +{ + PROFILE_SCOPE( ScriptedBehavior_onExit ); + onExit_callback(owner); +} + +Status ScriptedBehavior::behavior( SimObject *owner ) +{ + PROFILE_SCOPE( ScriptedBehavior_behavior ); + return behavior_callback( owner ); +} diff --git a/Engine/source/BadBehavior/leaf/ScriptedBehavior.h b/Engine/source/BadBehavior/leaf/ScriptedBehavior.h new file mode 100644 index 000000000..8dddc8f02 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/ScriptedBehavior.h @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SCRIPTEDBEHAVIOR_H_ +#define _BB_SCRIPTEDBEHAVIOR_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/behavior.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // ScriptedBehavior - A structured behavior leaf node which defines a series + // Of scripted callbacks + //--------------------------------------------------------------------------- + class ScriptedBehavior : public Behavior + { + typedef Behavior Parent; + + public: + ScriptedBehavior(); + + virtual bool precondition( SimObject *owner ); + virtual void onEnter( SimObject *owner ); + virtual void onExit( SimObject *owner ); + virtual Status behavior( SimObject *owner ); + + DECLARE_CONOBJECT(ScriptedBehavior); + DECLARE_CALLBACK(void, onEnter, (SimObject *owner)); + DECLARE_CALLBACK(void, onExit, (SimObject *owner)); + DECLARE_CALLBACK(bool, precondition, (SimObject *owner)); + DECLARE_CALLBACK(Status, behavior, (SimObject *owner)); + }; +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/SubTree.cpp b/Engine/source/BadBehavior/leaf/SubTree.cpp new file mode 100644 index 000000000..0bda8e3e5 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/SubTree.cpp @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "SubTree.h" + +#include "console/consoleTypes.h" + +using namespace BadBehavior; + + +//------------------------------------------------------------------------------ +// SubTree node - links to another behavior tree +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(SubTree); + +SubTree::SubTree() + : mSubTreeName(0) +{ +} + +void SubTree::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "subTreeName", TypeString, Offset(mSubTreeName, SubTree), + "@brief The name of the behavior tree that this node links to. Max 255 characters." ); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *SubTree::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + if(!mSubTreeName || mSubTreeName[0] == 0) + { + Con::errorf("SubTree::onInitialize: no sub tree specified"); + return NULL; + } + + SimObject *subTreeNode; + + if(!Sim::findObject(mSubTreeName, subTreeNode)) + { + Con::errorf("SubTree:onInitialize: the specified sub tree does not exist"); + return NULL; + } + + Node *node = dynamic_cast(subTreeNode); + if(!node) + { + Con::errorf("SubTree::onInitialize: the specified sub tree is not a behavior tree node"); + return NULL; + } + + return node->createTask(owner, runner); +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/SubTree.h b/Engine/source/BadBehavior/leaf/SubTree.h new file mode 100644 index 000000000..01481eb4d --- /dev/null +++ b/Engine/source/BadBehavior/leaf/SubTree.h @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_SUBTREE_H_ +#define _BB_SUBTREE_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // SubTree decorator + // Turns a named Behavior into a subtree of this node. + // Does not actually have a child, so is a subclass of leaf + //--------------------------------------------------------------------------- + class SubTree : public LeafNode + { + typedef LeafNode Parent; + + protected: + const char* mSubTreeName; + + public: + SubTree(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + DECLARE_CONOBJECT(SubTree); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/Wait.cpp b/Engine/source/BadBehavior/leaf/Wait.cpp new file mode 100644 index 000000000..e2dc014cd --- /dev/null +++ b/Engine/source/BadBehavior/leaf/Wait.cpp @@ -0,0 +1,115 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +#include "Wait.h" +#include "BadBehavior/core/Runner.h" + +#include "math/mMathFn.h" +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// Wait leaf node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(Wait); + +Wait::Wait() + : mWaitMs(1000) +{ +} + +void Wait::initPersistFields() +{ + addGroup( "Behavior" ); + + addProtectedField( "waitMs", TypeS32, Offset(mWaitMs, Wait), &_setWait, &defaultProtectedGetFn, + "The time in ms that the node should wait before completion." ); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +bool Wait::_setWait(void *object, const char *index, const char *data) +{ + Wait *node = static_cast( object ); + node->mWaitMs = getMax(0, dAtoi( data )); + return false; +} + +Task *Wait::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new WaitTask(*this, owner, runner); +} + +//------------------------------------------------------------------------------ +// Wait task +//------------------------------------------------------------------------------ +WaitTask::WaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mEventId(0) +{ +} + +WaitTask::~WaitTask() +{ + cancelEvent(); +} + +void WaitTask::cancelEvent() +{ + if(Sim::isEventPending(mEventId)) + { + Sim::cancelEvent(mEventId); + mEventId = 0; + } +} + +void WaitTask::onInitialize() +{ + Parent::onInitialize(); + cancelEvent(); +} + +void WaitTask::onTerminate() +{ + Parent::onTerminate(); + cancelEvent(); +} + +Task* WaitTask::update() +{ + if(mStatus == RESUME) + { + mStatus = SUCCESS; + mIsComplete = true; + } + else if(mStatus == INVALID) + { + mEventId = Sim::postEvent(mRunner, new TaskReactivateEvent(*this), Sim::getCurrentTime() + static_cast(mNodeRep)->getWaitMs()); + mStatus = SUSPENDED; + } + + return NULL; +} diff --git a/Engine/source/BadBehavior/leaf/Wait.h b/Engine/source/BadBehavior/leaf/Wait.h new file mode 100644 index 000000000..20a49ee01 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/Wait.h @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_WAIT_H_ +#define _BB_WAIT_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // Wait leaf + // Pauses for a set time period. + //--------------------------------------------------------------------------- + class Wait : public LeafNode + { + typedef LeafNode Parent; + + protected: + static bool _setWait(void *object, const char *index, const char *data); + + S32 mWaitMs; + + public: + Wait(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + S32 getWaitMs() const { return mWaitMs; } + + DECLARE_CONOBJECT(Wait); + }; + + //--------------------------------------------------------------------------- + // Wait leaf task + //--------------------------------------------------------------------------- + class WaitTask : public Task + { + typedef Task Parent; + + protected: + U32 mEventId; + + virtual void onInitialize(); + virtual void onTerminate(); + virtual Task* update(); + + void cancelEvent(); + + public: + WaitTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~WaitTask(); + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/WaitForSignal.cpp b/Engine/source/BadBehavior/leaf/WaitForSignal.cpp new file mode 100644 index 000000000..1373a6d2d --- /dev/null +++ b/Engine/source/BadBehavior/leaf/WaitForSignal.cpp @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "WaitForSignal.h" +#include "BadBehavior/core/Runner.h" + +#include "console/consoleTypes.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// WaitForSignal leaf node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(WaitForSignal); + +WaitForSignal::WaitForSignal() + : mTimeoutMs(0) +{ +} + +void WaitForSignal::initPersistFields() +{ + addGroup( "Behavior" ); + + addField( "signalName", TypeRealString, Offset(mSignalName, WaitForSignal), + "The time in ms that the node should wait before completion." ); + + addProtectedField( "timeoutMs", TypeS32, Offset(mTimeoutMs, WaitForSignal), &_setTimeout, &defaultProtectedGetFn, + "The maximum time in ms that the node should wait for the signal.\n" + "A value of 0 indicates no limit"); + + endGroup( "Behavior" ); + + Parent::initPersistFields(); +} + +Task *WaitForSignal::createTask(SimObject &owner, BehaviorTreeRunner &runner) +{ + return new WaitForSignalTask(*this, owner, runner); +} + +bool WaitForSignal::_setTimeout(void *object, const char *index, const char *data) +{ + WaitForSignal *node = static_cast( object ); + node->mTimeoutMs = getMax(0, dAtoi( data )); + return false; +} + +//------------------------------------------------------------------------------ +// Wait task +//------------------------------------------------------------------------------ +WaitForSignalTask::WaitForSignalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner) + : Parent(node, owner, runner), + mEventId(0) +{ +} + +WaitForSignalTask::~WaitForSignalTask() +{ + unsubscribe(); + cancelEvent(); +} + +void WaitForSignalTask::subscribe() +{ + mRunner->subscribeToSignal(static_cast(mNodeRep)->getSignalName().c_str(), this); +} + +void WaitForSignalTask::unsubscribe() +{ + mRunner->unsubscribeFromSignal(static_cast(mNodeRep)->getSignalName().c_str(), this); +} + +void WaitForSignalTask::onSignal() +{ + onResume(); +} + +void WaitForSignalTask::onTimeout() +{ + mStatus = FAILURE; +} + +void WaitForSignalTask::cancelEvent() +{ + if(mEventId != 0 && Sim::isEventPending(mEventId)) + { + Sim::cancelEvent(mEventId); + mEventId = 0; + } +} + +void WaitForSignalTask::onInitialize() +{ + Parent::onInitialize(); + subscribe(); + cancelEvent(); +} + +void WaitForSignalTask::onTerminate() +{ + Parent::onTerminate(); + unsubscribe(); + cancelEvent(); +} + +Task* WaitForSignalTask::update() +{ + if(mStatus == RESUME) + { + mStatus = SUCCESS; + } + else if (mStatus == INVALID) + { + mStatus = SUSPENDED; + + S32 timeout = static_cast(mNodeRep)->getTimeoutMs(); + if(timeout > 0) + mEventId = Sim::postEvent(mRunner, new WaitForSignalTimeoutEvent(*this), Sim::getCurrentTime() + timeout); + } + + if(mStatus == SUCCESS || mStatus == FAILURE) + mIsComplete = true; + + return NULL; +} diff --git a/Engine/source/BadBehavior/leaf/WaitForSignal.h b/Engine/source/BadBehavior/leaf/WaitForSignal.h new file mode 100644 index 000000000..5758cd19a --- /dev/null +++ b/Engine/source/BadBehavior/leaf/WaitForSignal.h @@ -0,0 +1,114 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_WAITFORSIGNAL_H_ +#define _BB_WAITFORSIGNAL_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/Core.h" +#endif +#ifndef _BB_SIGNAL_H_ +#include "BadBehavior/core/Signal.h" +#endif +#ifndef _SIMEVENTS_H_ +#include "console/simEvents.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // WaitForSignal leaf + // Waits until it receives the requested signal. + //--------------------------------------------------------------------------- + class WaitForSignal : public LeafNode + { + typedef LeafNode Parent; + + protected: + String mSignalName; + S32 mTimeoutMs; + + static bool _setTimeout(void *object, const char *index, const char *data); + + public: + WaitForSignal(); + + virtual Task *createTask(SimObject &owner, BehaviorTreeRunner &runner); + + static void initPersistFields(); + + const String &getSignalName() const { return mSignalName; } + S32 getTimeoutMs() const { return mTimeoutMs; } + + DECLARE_CONOBJECT(WaitForSignal); + }; + + //--------------------------------------------------------------------------- + // WaitForSignal leaf task + //--------------------------------------------------------------------------- + class WaitForSignalTask : public Task, public virtual SignalSubscriber + { + typedef Task Parent; + + protected: + U32 mEventId; + + virtual void onInitialize(); + virtual void onTerminate(); + virtual Task* update(); + + void cancelEvent(); + + // SignalSubscriber + virtual void subscribe(); + virtual void unsubscribe(); + + public: + WaitForSignalTask(Node &node, SimObject &owner, BehaviorTreeRunner &runner); + virtual ~WaitForSignalTask(); + + // SignalSubscriber + virtual void onSignal(); + + // timeout + void onTimeout(); + }; + + + class WaitForSignalTimeoutEvent : public SimEvent + { + WaitForSignalTask *mTask; + public: + WaitForSignalTimeoutEvent(WaitForSignalTask &task) + { + mTask = &task; + } + + void process( SimObject *object ) + { + mTask->onTimeout(); + } + }; + +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.cpp b/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.cpp new file mode 100644 index 000000000..ae96a7c81 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.cpp @@ -0,0 +1,109 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "followBehaviorAction.h" + +#include "T3D/aiPlayer.h" + +using namespace BadBehavior; + +//------------------------------------------------------------------------------ +// FollowBehavior node +//------------------------------------------------------------------------------ +IMPLEMENT_CONOBJECT(FollowBehaviorAction); + +FollowBehaviorAction::FollowBehaviorAction() +{ +} + +bool FollowBehaviorAction::precondition( SimObject *owner ) +{ + PROFILE_SCOPE( FollowBehaviorAction_precondition); + + // check that our owner is an AIPlayer + AIPlayer *aiPlayer = dynamic_cast(owner); + if(!aiPlayer) + return false; + + return true; +} + +void FollowBehaviorAction::onEnter( SimObject *owner ) +{ + //PROFILE_SCOPE( FollowBehaviorAction_onEnter ); +} + +void FollowBehaviorAction::onExit( SimObject *owner ) +{ + //PROFILE_SCOPE( FollowBehaviorAction_onExit ); +} + +Status FollowBehaviorAction::behavior( SimObject *owner ) +{ + PROFILE_SCOPE( FollowBehaviorAction_behavior ); + + // get the owning AIPlayer object + AIPlayer *aiPlayer = dynamic_cast(owner); + if(!aiPlayer) + return FAILURE; + + // get the script-specified followObject + const char *followFieldName = StringTable->insert("followObject"); + const char *followFieldValue = owner->getDataField(followFieldName, NULL); + if(!followFieldValue || !followFieldValue[0]) + return FAILURE; + + SimObject *followSimObj = Sim::findObject(dAtoi(followFieldValue)); + if(!followSimObj) + return FAILURE; + + // check that the follow object is a SceneObject + SceneObject *followObject = dynamic_cast(followSimObj); + if(!followObject) + return FAILURE; + + // get the script-specified followDistance field + const char *distanceFieldName = StringTable->insert("followDistance"); + const char *distanceFieldValue = owner->getDataField(distanceFieldName, NULL); + float followDistance = 1.f; + if(distanceFieldValue && distanceFieldValue[0]) + followDistance = dAtof(distanceFieldValue); + + // try and stay at followDistance from the followObject + Point3F targetPos = followObject->getPosition(); + Point3F followVec = aiPlayer->getPosition() - targetPos; + + // get current distance (ignore z component) + F32 curDist = Point3F(followVec.x, followVec.y, 0.f).len(); + + if(mFabs(curDist - followDistance) > aiPlayer->getMoveTolerance()) + { + followVec.normalize(); + followVec *= followDistance; + Point3F destination = targetPos + followVec; + + aiPlayer->setMoveDestination(destination, true); + return RUNNING; + } + + return SUCCESS; +} diff --git a/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.h b/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.h new file mode 100644 index 000000000..9410c0324 --- /dev/null +++ b/Engine/source/BadBehavior/leaf/compiled/followBehaviorAction.h @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BB_FOLLOWBEHAVIORACTION_H_ +#define _BB_FOLLOWBEHAVIORACTION_H_ + +#ifndef _BB_CORE_H_ +#include "BadBehavior/core/behavior.h" +#endif + +namespace BadBehavior +{ + //--------------------------------------------------------------------------- + // FollowBehaviorAction - Make an AIPlayer follow another object + // Demonstrates how to create a compiled behavior by subclassing Behavior + //--------------------------------------------------------------------------- + class FollowBehaviorAction : public Behavior + { + typedef Behavior Parent; + + public: + FollowBehaviorAction(); + + virtual bool precondition( SimObject *owner ); + virtual void onEnter( SimObject *owner ); + virtual void onExit( SimObject *owner ); + virtual Status behavior( SimObject *owner ); + + DECLARE_CONOBJECT(FollowBehaviorAction); + }; +} // namespace BadBehavior + +#endif \ No newline at end of file diff --git a/Engine/source/BadBehavior/tools/BTUndoActions.cpp b/Engine/source/BadBehavior/tools/BTUndoActions.cpp new file mode 100644 index 000000000..a7ad0200f --- /dev/null +++ b/Engine/source/BadBehavior/tools/BTUndoActions.cpp @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "BTUndoActions.h" + +#include "console/consoleTypes.h" +#include "console/simSet.h" + +S32 getNextObjectInGroup(SimObject *object, SimGroup *group) +{ + group->lock(); + S32 nextId = -1; + + if(object != group->last() && group->find( group->begin(), group->end(), object ) != group->end()) + { + for( SimSet::iterator i = group->begin(); i != group->end(); i++) + { + if( *i == object ) + { + nextId = (*++i)->getId(); + break; + } + } + group->unlock(); + } + + return nextId; +} + +IMPLEMENT_CONOBJECT( BTDeleteUndoAction ); + +ConsoleDocClass( BTDeleteUndoAction, + "@brief Behavior Tree Editor delete undo instance\n\n" + "Not intended for game development, for editors or internal use only.\n\n " + "@internal"); + +BTDeleteUndoAction::BTDeleteUndoAction( const UTF8 *actionName ) + : UndoAction( actionName ) +{ +} + +BTDeleteUndoAction::~BTDeleteUndoAction() +{ +} + +void BTDeleteUndoAction::initPersistFields() +{ + Parent::initPersistFields(); +} + +void BTDeleteUndoAction::deleteObject( SimObject *object ) +{ + AssertFatal( object, "BTDeleteUndoAction::deleteObject() - Got null object!" ); + AssertFatal( object->isProperlyAdded(), + "BTDeleteUndoAction::deleteObject() - Object should be registered!" ); + + // Capture the object id. + mObject.id = object->getId(); + + // Save the state. + mObject.memento.save( object ); + + // Store the group. + SimGroup *group = object->getGroup(); + if ( group ) + { + mObject.groupId = group->getId(); + + // and the next object in the group + mObject.nextId = getNextObjectInGroup(object, group); + } + + // Now delete the object. + object->deleteObject(); +} + +ConsoleMethod( BTDeleteUndoAction, deleteObject, void, 3, 3, "( SimObject obj )") +{ + SimObject *obj = NULL; + if ( Sim::findObject( argv[2], obj ) && obj ) + object->deleteObject( obj ); +} + +void BTDeleteUndoAction::undo() +{ + // Create the object. + SimObject::setForcedId(mObject.id); // Restore the object's Id + SimObject *object = mObject.memento.restore(); + if ( !object ) + return; + + // Now restore its group. + SimGroup *group; + if ( Sim::findObject( mObject.groupId, group ) ) + { + group->addObject( object ); + + // restore its position in the group + SimObject *nextObj; + if ( Sim::findObject( mObject.nextId, nextObj ) ) + { + group->reOrder(object, nextObj); + } + } + + Con::executef( this, "onUndone" ); +} + +void BTDeleteUndoAction::redo() +{ + SimObject *object = Sim::findObject( mObject.id ); + if ( object ) + object->deleteObject(); + + Con::executef( this, "onRedone" ); +} diff --git a/Engine/source/BadBehavior/tools/BTUndoActions.h b/Engine/source/BadBehavior/tools/BTUndoActions.h new file mode 100644 index 000000000..931e53e1e --- /dev/null +++ b/Engine/source/BadBehavior/tools/BTUndoActions.h @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _BT_UNDO_ACTIONS_H_ +#define _BT_UNDO_ACTIONS_H_ + +#ifndef _UNDO_H_ +#include "util/undo.h" +#endif +#ifndef _CONSOLE_SIMOBJECTMEMENTO_H_ +#include "console/simObjectMemento.h" +#endif + +S32 getNextObjectInSet(SimObject *obj, SimGroup &group); + +class BTDeleteUndoAction : public UndoAction +{ + typedef UndoAction Parent; + +protected: + + struct ObjectState + { + /// The object we deleted and will restore in undo. + SimObjectId id; + + /// The captured object state. + SimObjectMemento memento; + + /// Keep track of the parent group. + SimObjectId groupId; + + /// Keep track of the position within the parent group + SimObjectId nextId; + }; + + /// The object we're deleting. + ObjectState mObject; + +public: + + DECLARE_CONOBJECT( BTDeleteUndoAction ); + static void initPersistFields(); + + BTDeleteUndoAction( const UTF8* actionName = "Delete Object" ); + virtual ~BTDeleteUndoAction(); + + /// + void deleteObject( SimObject *object ); + + // UndoAction + virtual void undo(); + virtual void redo(); +}; + + + +#endif // _BT_UNDO_ACTIONS_H_ \ No newline at end of file diff --git a/Engine/source/BadBehavior/tools/guiBTViewCtrl.cpp b/Engine/source/BadBehavior/tools/guiBTViewCtrl.cpp new file mode 100644 index 000000000..32e455f3e --- /dev/null +++ b/Engine/source/BadBehavior/tools/guiBTViewCtrl.cpp @@ -0,0 +1,301 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "guiBTViewCtrl.h" + +#include "gfx/gfxDrawUtil.h" +#include "gui/worldEditor/editorIconRegistry.h" +#include "gui/controls/guiTextEditCtrl.h" + +using namespace BadBehavior; + +IMPLEMENT_CONOBJECT(GuiBehaviorTreeViewCtrl); + +void GuiBehaviorTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool ) +{ + if( !mVisibleItems.size() ) + return; + + // Do some sanity checking and data retrieval. + AssertFatal(cell.y < mVisibleItems.size(), "GuiTreeViewCtrl::onRenderCell: invalid cell"); + Item * item = mVisibleItems[cell.y]; + + // If there's no object, deal with it. + if(item->isInspectorData()) + if(!item->getObject()) + return; + + RectI drawRect( offset, mCellSize ); + GFXDrawUtil *drawer = GFX->getDrawUtil(); + drawer->clearBitmapModulation(); + + FrameAllocatorMarker txtBuff; + + // Ok, we have the item. There are a few possibilities at this point: + // - We need to draw inheritance lines and a treeview-chosen icon + // OR + // - We have to draw an item-dependent icon + // - If we're mouseover, we have to highlight it. + // + // - We have to draw the text for the item + // - Taking into account various mouseover states + // - Taking into account the value (set or not) + // - If it's an inspector data, we have to do some custom rendering + // - ADDED: If it is being renamed, we also have custom rendering. + + // Ok, first draw the tab and icon. + + // Do we draw the tree lines? + if( mFlags.test(ShowTreeLines) ) + { + drawRect.point.x += ( mTabSize * item->mTabLevel ); + Item* parent = item->mParent; + for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- ) + { + drawRect.point.x -= mTabSize; + if ( parent->mNext ) + drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpLine] ); + + parent = parent->mParent; + } + } + + // Now, the icon... + drawRect.point.x = offset.x + mTabSize * item->mTabLevel; + + // First, draw the rollover glow, if it's an inner node. + if ( item->isParent() && item->mState.test( Item::MouseOverBmp ) ) + drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpGlow] ); + + // Now, do we draw a treeview-selected item or an item dependent one? + S32 newOffset = 0; // This is stored so we can render glow, then update render pos. + + S32 bitmap = 0; + + // Ok, draw the treeview lines as appropriate. + + bool drawBitmap = true; + if ( !item->isParent() ) + { + if( mFlags.test( ShowTreeLines ) ) + { + if( ( item->mNext && item->mPrevious ) + || ( item->mNext && item->mParent && ( !_isRootLevelItem( item ) || mShowRoot ) ) ) + bitmap = BmpChild; + else if( item->mNext && ( !item->mParent || !mShowRoot ) ) + bitmap = BmpFirstChild; + else if( item->mPrevious || ( item->mParent && !_isRootLevelItem( item ) ) ) + bitmap = BmpLastChild; + else + drawBitmap = false; + } + else + drawBitmap = false; + } + else + { + bitmap = item->isExpanded() ? BmpExp : BmpCon; + + if( mFlags.test( ShowTreeLines ) ) + { + // Shift indices to show versions with tree lines. + + if ( item->mParent || item->mPrevious ) + bitmap += ( item->mNext ? 3 : 2 ); + else + bitmap += ( item->mNext ? 1 : 0 ); + } + } + + if( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) ) + { + if( drawBitmap ) + drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[bitmap] ); + newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x; + } + + if(item->isInspectorData()) + { + // draw lock icon if need be + S32 icon = Lock1; + S32 icon2 = Hidden; + + if (item->getObject() && item->getObject()->isLocked()) + { + if (mIconTable[icon]) + { + //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth(); + drawRect.point.x += mIconTable[icon].getWidth(); + drawer->drawBitmap( mIconTable[icon], drawRect.point ); + } + } + + if (item->getObject() && item->getObject()->isHidden()) + { + if (mIconTable[icon2]) + { + //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth(); + drawRect.point.x += mIconTable[icon2].getWidth(); + drawer->drawBitmap( mIconTable[icon2], drawRect.point ); + } + } + + /*SimObject * pObject = item->getObject(); + SimGroup * pGroup = ( pObject == NULL ) ? NULL : dynamic_cast( pObject ); + + // If this item is a VirtualParent we can use the generic SimGroup123 icons. + // However if there is already an icon in the EditorIconRegistry for this + // exact class (not counting parent class icons) we want to use that instead. + bool hasClassIcon = gEditorIcons.hasIconNoRecurse( pObject ); + + // draw the icon associated with the item + if ( !hasClassIcon && item->mState.test(Item::VirtualParent)) + { + if ( pGroup != NULL) + { + if (item->isExpanded()) + item->mIcon = SimGroup1; + else + item->mIcon = SimGroup2; + } + else + item->mIcon = SimGroup2; + } + + if ( !hasClassIcon && item->mState.test(Item::Marked)) + { + if (item->isInspectorData()) + { + if ( pGroup != NULL ) + { + if (item->isExpanded()) + item->mIcon = SimGroup3; + else + item->mIcon = SimGroup4; + } + } + }*/ + + GFXTexHandle iconHandle; + + if ( ( item->mIcon != -1 ) && mIconTable[item->mIcon] ) + iconHandle = mIconTable[item->mIcon]; +#ifdef TORQUE_TOOLS + else + iconHandle = gEditorIcons.findIcon( item->getObject() ); +#endif + + if ( iconHandle.isValid() ) + { + S32 iconHeight = (mItemHeight - iconHandle.getHeight()) / 2; + S32 oldHeight = drawRect.point.y; + if(iconHeight > 0) + drawRect.point.y += iconHeight; + drawRect.point.x += iconHandle.getWidth(); + drawer->drawBitmap( iconHandle, drawRect.point ); + drawRect.point.y = oldHeight; + } + } + else + { + S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage; + if ( icon ) + { + if (mIconTable[icon]) + { + S32 iconHeight = (mItemHeight - mIconTable[icon].getHeight()) / 2; + S32 oldHeight = drawRect.point.y; + if(iconHeight > 0) + drawRect.point.y += iconHeight; + drawRect.point.x += mIconTable[icon].getWidth(); + drawer->drawBitmap( mIconTable[icon], drawRect.point ); + drawRect.point.y = oldHeight; + } + } + } + + // Ok, update offset so we can render some text! + drawRect.point.x += newOffset; + + // Ok, now we're off to rendering the actual data for the treeview item. + + U32 bufLen = 1024; //item->mDataRenderWidth + 1; + char *displayText = (char *)txtBuff.alloc(bufLen); + displayText[bufLen-1] = 0; + item->getDisplayText(bufLen, displayText); + + // Draw the rollover/selected bitmap, if one was specified. + drawRect.extent.x = mProfile->mFont->getStrWidth( displayText ) + ( 2 * mTextOffset ); + if ( item->mState.test( Item::Selected ) && mTexSelected ) + drawer->drawBitmapStretch( mTexSelected, drawRect ); + else if ( item->mState.test( Item::MouseOverText ) && mTexRollover ) + drawer->drawBitmapStretch( mTexRollover, drawRect ); + + // Offset a bit so as to space text properly. + drawRect.point.x += mTextOffset; + + // Determine what color the font should be. + ColorI fontColor; + + fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSEL : + ( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor ); + + if (item->mState.test(Item::Selected)) + { + drawer->drawRectFill(drawRect, mProfile->mFillColorSEL); + } + else if (item->mState.test(Item::MouseOverText)) + { + drawer->drawRectFill(drawRect, mProfile->mFillColorHL); + } + + if( item->mState.test(Item::MouseOverText) ) + { + fontColor = mProfile->mFontColorHL; + } + + drawer->setBitmapModulation( fontColor ); + + // Center the text horizontally. + S32 height = (mItemHeight - mProfile->mFont->getHeight()) / 2; + + if(height > 0) + drawRect.point.y += height; + + // JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline + drawRect.point.x += 2; + + drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontColors ); + + if ( mRenamingItem == item && mRenameCtrl ) + { + Point2I ctrPos = globalToLocalCoord( drawRect.point ); + ctrPos.y -= height; + ctrPos.x -= 2; + + Point2I ctrExtent( getWidth() - ctrPos.x, drawRect.extent.y ); + + mRenameCtrl->setPosition( ctrPos ); + mRenameCtrl->setExtent( ctrExtent ); + mRenameCtrl->setVisible( true ); + } +} \ No newline at end of file diff --git a/Engine/source/BadBehavior/tools/guiBTViewCtrl.h b/Engine/source/BadBehavior/tools/guiBTViewCtrl.h new file mode 100644 index 000000000..9800f2d67 --- /dev/null +++ b/Engine/source/BadBehavior/tools/guiBTViewCtrl.h @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 Guy Allard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _GUI_BTVIEWCTRL_H_ +#define _GUI_BTVIEWCTRL_H_ + +#ifndef _GUI_TREEVIEWCTRL_H +#include "gui/controls/guiTreeViewCtrl.h" +#endif + +namespace BadBehavior +{ + // subclassing GuiTreeViewCtrl so that we can tweak it for the behavior tree editor + class GuiBehaviorTreeViewCtrl : public GuiTreeViewCtrl + { + typedef GuiTreeViewCtrl Parent; + + public: + void onRenderCell(Point2I offset, Point2I cell, bool, bool); + + DECLARE_CONOBJECT(GuiBehaviorTreeViewCtrl); + }; + +} // namespace BadBehavior + +#endif diff --git a/Templates/Empty/buildFiles/config/projectCode.conf b/Templates/Empty/buildFiles/config/projectCode.conf index 57348ea8e..395a8e2fb 100644 --- a/Templates/Empty/buildFiles/config/projectCode.conf +++ b/Templates/Empty/buildFiles/config/projectCode.conf @@ -9,4 +9,5 @@ // In this case all the code in the "custom" folder in your project's source directory would be added // addSrcDir('../source/custom'); + includeModule("BadBehavior"); ?> \ No newline at end of file diff --git a/Templates/Full/buildFiles/config/projectCode.conf b/Templates/Full/buildFiles/config/projectCode.conf index 57348ea8e..395a8e2fb 100644 --- a/Templates/Full/buildFiles/config/projectCode.conf +++ b/Templates/Full/buildFiles/config/projectCode.conf @@ -9,4 +9,5 @@ // In this case all the code in the "custom" folder in your project's source directory would be added // addSrcDir('../source/custom'); + includeModule("BadBehavior"); ?> \ No newline at end of file diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 4373f7268..c835c161e 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -219,6 +219,13 @@ addPath("${srcDir}/platform/input") addPath("${srcDir}/platform/output") addPath("${srcDir}/app") addPath("${srcDir}/app/net") +addPath("${srcDir}/BadBehavior") +addPath("${srcDir}/BadBehavior/composite") +addPath("${srcDir}/BadBehavior/core") +addPath("${srcDir}/BadBehavior/decorator") +addPath("${srcDir}/BadBehavior/leaf") +addPath("${srcDir}/BadBehavior/leaf/compiled") +addPath("${srcDir}/BadBehavior/tools") addPath("${srcDir}/util/messaging") addPath("${srcDir}/gfx/Null") addPath("${srcDir}/gfx/test")