[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/BehaviorTree/BehaviorTree.CPP/master/src/action_node.cpp [Back]  [Original]

/* Copyright (C) 2015-2018 Michele Colledanchise -  All Rights Reserved
 * Copyright (C) 2018-2025 Davide Faconti -  All Rights Reserved
*
*   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.
*/

#define MINICORO_IMPL
#include "behaviortree_cpp/action_node.h"

#include "minicoro.h"

#include 

using namespace BT;

ActionNodeBase::ActionNodeBase(const std::string& name, const NodeConfig& config)
  : LeafNode::LeafNode(name, config)
{}

//-------------------------------------------------------

SimpleActionNode::SimpleActionNode(const std::string& name,
                                   SimpleActionNode::TickFunctor tick_functor,
                                   const NodeConfig& config)
  : SyncActionNode(name, config), tick_functor_(std::move(tick_functor))
{}

NodeStatus SimpleActionNode::tick()
{
  NodeStatus prev_status = status();

  if(prev_status == NodeStatus::IDLE)
  {
    setStatus(NodeStatus::RUNNING);
    prev_status = NodeStatus::RUNNING;
  }

  const NodeStatus status = tick_functor_(*this);
  if(status != prev_status)
  {
    setStatus(status);
  }
  return status;
}

//-------------------------------------------------------

SyncActionNode::SyncActionNode(const std::string& name, const NodeConfig& config)
  : ActionNodeBase(name, config)
{}

NodeStatus SyncActionNode::executeTick()
{
  auto stat = ActionNodeBase::executeTick();
  if(stat == NodeStatus::RUNNING)
  {
    throw LogicError("SyncActionNode MUST never return RUNNING");
  }
  return stat;
}

//-------------------------------------

struct CoroActionNode::Pimpl
{
  mco_coro* coro = nullptr;
  mco_desc desc = {};
};

namespace
{
void CoroEntry(mco_coro* co)
{
  static_cast(co->user_data)->tickImpl();
}
}  // namespace

CoroActionNode::CoroActionNode(const std::string& name, const NodeConfig& config)
  : ActionNodeBase(name, config), _p(new Pimpl)
{}

CoroActionNode::~CoroActionNode()
{
  try
  {
    destroyCoroutine();
  }
  catch(const std::exception& ex)
  {
    std::cerr desc = mco_desc_init(CoroEntry, 0);
    _p->desc.user_data = this;

    const mco_result res = mco_create(&_p->coro, &_p->desc);
    if(res != MCO_SUCCESS)
    {
      throw RuntimeError("Can't create coroutine");
    }
  }

  //------------------------
  // execute the coroutine
  mco_resume(_p->coro);
  //------------------------

  // check if the coroutine finished. In this case, destroy it
  if(mco_status(_p->coro) == MCO_DEAD)
  {
    destroyCoroutine();
  }

  return status();
}

void CoroActionNode::tickImpl()
{
  setStatus(TreeNode::executeTick());
}

void CoroActionNode::halt()
{
  destroyCoroutine();
  resetStatus();  // might be redundant
}

void CoroActionNode::destroyCoroutine()
{
  if(_p->coro != nullptr)
  {
    const mco_result res = mco_destroy(_p->coro);
    if(res != MCO_SUCCESS)
    {
      throw RuntimeError("Can't destroy coroutine");
    }
    _p->coro = nullptr;
  }
}

bool StatefulActionNode::isHaltRequested() const
{
  return halt_requested_.load();
}

NodeStatus StatefulActionNode::tick()
{
  const NodeStatus prev_status = status();

  if(prev_status == NodeStatus::IDLE)
  {
    const NodeStatus new_status = onStart();
    if(new_status == NodeStatus::IDLE)
    {
      throw LogicError("StatefulActionNode::onStart() must not return IDLE");
    }
    return new_status;
  }
  //------------------------------------------
  if(prev_status == NodeStatus::RUNNING)
  {
    const NodeStatus new_status = onRunning();
    if(new_status == NodeStatus::IDLE)
    {
      throw LogicError("StatefulActionNode::onRunning() must not return IDLE");
    }
    return new_status;
  }
  return prev_status;
}

void StatefulActionNode::halt()
{
  halt_requested_.store(true);
  if(status() == NodeStatus::RUNNING)
  {
    onHalted();
  }
  resetStatus();  // might be redundant
}

NodeStatus BT::ThreadedAction::executeTick()
{
  using lock_type = std::unique_lock;
  //send signal to other thread.
  // The other thread is in charge for changing the status
  if(status() == NodeStatus::IDLE)
  {
    setStatus(NodeStatus::RUNNING);
    halt_requested_ = false;
    thread_handle_ = std::async(std::launch::async, [this]() {
      try
      {
        auto status = tick();
        if(!isHaltRequested())
        {
          setStatus(status);
        }
      }
      catch(std::exception&)
      {
        std::cerr 

Web Proxy Viewer  |  New URL  |  Original Page