/*******************************************************************************
* Copyright 2014 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.ai.btree.decorator;
import com.badlogic.gdx.ai.btree.Decorator;
import com.badlogic.gdx.ai.btree.Task;
import com.badlogic.gdx.ai.btree.TaskCloneException;
import com.badlogic.gdx.ai.btree.annotation.TaskAttribute;
import com.badlogic.gdx.ai.btree.annotation.TaskConstraint;
import com.badlogic.gdx.ai.btree.utils.BehaviorTreeLibraryManager;
/** An {@code Include} decorator grafts a subtree. When the subtree is grafted depends on the value of the {@link #lazy} attribute:
* at clone-time if is {@code false}, at run-time if is {@code true}.
*
* @param <E> type of the blackboard object that tasks use to read or modify game state
*
* @author davebaol
* @author implicit-invocation */
@TaskConstraint(minChildren = 0, maxChildren = 0)
public class Include<E> extends Decorator<E> {
/** Mandatory task attribute indicating the path of the subtree to include. */
@TaskAttribute(required = true) public String subtree;
/** Optional task attribute indicating whether the subtree should be included at clone-time ({@code false}, the default) or at
* run-time ({@code true}). */
@TaskAttribute public boolean lazy;
/** Creates a non-lazy {@code Include} decorator without specifying the subtree. */
public Include () {
}
/** Creates a non-lazy {@code Include} decorator for the specified subtree.
* @param subtree the subtree reference, usually a path */
public Include (String subtree) {
this.subtree = subtree;
}
/** Creates an eager or lazy {@code Include} decorator for the specified subtree.
* @param subtree the subtree reference, usually a path
* @param lazy whether inclusion should happen at clone-time (false) or at run-time (true) */
public Include (String subtree, boolean lazy) {
this.subtree = subtree;
this.lazy = lazy;
}
/** The first call of this method lazily sets its child to the referenced subtree created through the
* {@link BehaviorTreeLibraryManager}. Subsequent calls do nothing since the child has already been set. A
* {@link UnsupportedOperationException} is thrown if this {@code Include} is eager.
*
* @throws UnsupportedOperationException if this {@code Include} is eager */
@Override
public void start () {
if (!lazy)
throw new UnsupportedOperationException("A non-lazy " + Include.class.getSimpleName() + " isn't meant to be run!");
if (child == null) {
// Lazy include is grafted at run-time
addChild(createSubtreeRootTask());
}
}
/** Returns a clone of the referenced subtree if this {@code Import} is eager; otherwise returns a clone of itself. */
@Override
public Task<E> cloneTask () {
if (lazy) return super.cloneTask();
// Non lazy include is grafted at clone-time
return createSubtreeRootTask();
}
/** Copies this {@code Include} to the given task. A {@link TaskCloneException} is thrown if this {@code Include} is eager.
* @param task the task to be filled
* @return the given task for chaining
* @throws TaskCloneException if this {@code Include} is eager. */
@Override
protected Task<E> copyTo (Task<E> task) {
if (!lazy) throw new TaskCloneException("A non-lazy " + getClass().getSimpleName() + " should never be copied.");
Include<E> include = (Include<E>)task;
include.subtree = subtree;
include.lazy = lazy;
return task;
}
private Task<E> createSubtreeRootTask () {
return BehaviorTreeLibraryManager.getInstance().createRootTask(subtree);
}
}