Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.l2jserver.gameserver.ai.ext;
- import com.l2jserver.Config;
- import com.l2jserver.gameserver.GameServer;
- import com.l2jserver.gameserver.ThreadPoolManager;
- import com.l2jserver.gameserver.ai.ext.struct.task.AITaskSimpleVar;
- import com.l2jserver.gameserver.ai.ext.tasks.AbstractAITask;
- import com.l2jserver.gameserver.ai.ext.tasks.interfaces.TaskQueueProc;
- import com.l2jserver.gameserver.ai.ext.tasks.util.RndTaskSelector;
- import com.l2jserver.gameserver.ext.util.ExtUtil;
- import com.l2jserver.gameserver.model.actor.L2Character;
- import com.l2jserver.gameserver.model.interfaces.ITaskQueueController;
- import com.l2jserver.util.Rnd;
- import javolution.util.FastComparator;
- import javolution.util.FastList;
- import javolution.util.FastMap;
- import java.util.Collection;
- import java.util.ListIterator;
- import java.util.concurrent.ScheduledFuture;
- import java.util.concurrent.locks.ReentrantLock;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- /**
- * ==============================================<br>
- * AI TaskQueue - MMOPlay project AI TaskQueue extension.<br>
- * ==============================================<br>
- *
- * @author Deedlit(deedlit @ protonmail.com)
- * @version 1.7.9.91
- */
- public class AI_TaskQueue extends AI_AbstractHelper implements Runnable
- {
- public static final Logger _log = Logger.getLogger("AI_TaskQueue");
- /* ------------------ AI queued tasks holders ---------------------------- */
- private FastList<AbstractAITask> _queuedTasks = new FastList<AbstractAITask>().shared();
- private RndTaskSelector _rndTaskSelector = new RndTaskSelector();
- /* ------------------ Task execution data holders ---------------------------- */
- private FastMap<Integer, Long[]> _taskByTypeExecCountAndTimestamps = new FastMap<Integer, Long[]>().shared();
- /* ------------------ Other fields ---------------------------- */
- private int taskIntervalMs = 100;
- private String _taskQueueName = "AI_TaskQueue";
- private volatile boolean _executingQueueTask = false;
- private ScheduledFuture<?> _taskQueueThread = null;
- private volatile boolean _performThinkTask = true;
- private boolean _variablesInitialized = false;
- private ReentrantLock _lock = new ReentrantLock(true);
- /* ------------------ Task variables map ---------------------------- */
- private FastMap<String, AITaskSimpleVar> _tasksVariables;
- /* ------------------- Task queue proc. interface for processing task queue tasks, depending on where queue is used (character AI, formation AI, zone AI, player AI etc...) ------------------ */
- private TaskQueueProc tqp;
- private ITaskQueueController _controller;
- //===================================================== CONSTRUCTORS =====================================================
- /**
- * @param controller
- * @param taskQueueName
- * @param tqp
- * @param taskIntervalMs
- */
- public AI_TaskQueue(ITaskQueueController controller, String taskQueueName, TaskQueueProc tqp, int taskIntervalMs)
- {
- super(controller.getController() instanceof L2Character ? ((L2Character)controller.getController()) : null);
- _controller = controller;
- _taskQueueName = taskQueueName;
- this.tqp = tqp;
- if (taskIntervalMs >= 50)
- this.taskIntervalMs = taskIntervalMs;
- _tasksVariables = new FastMap<String, AITaskSimpleVar>().shared();
- // initialize task queue internal variables
- initDefaultTasksVariables();
- }
- //===================================================== MAIN BODY =====================================================
- /**
- * Start task queue main thread.
- */
- public synchronized void startTaskQueue()
- {
- runCleanup = false;
- execNextRandomTaskCounter = 0;
- // setLockingEnabled(Config.AI_TASK_QUEUE_LOCKING);
- if (_taskQueueThread == null)
- {
- _taskQueueThread = Config.AI_TASK_QUEUE_USE_THREAD_POOL_EXECUTOR ? ThreadPoolManager.getInstance().scheduleAiTaskAtFixedRate(this, Rnd.qget(200, 750), taskIntervalMs) :
- ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(this, Rnd.qget(200, 750), taskIntervalMs);
- initDefaultTasksVariables();
- }
- }
- /**
- * Stop task queue main thread.
- */
- public synchronized void stopTaskQueue()
- {
- if (_taskQueueThread != null)
- {
- _performThinkTask = true;
- _taskQueueThread.cancel(false);
- _taskQueueThread = null;
- // _queuedTasks.clear();
- // _rndTaskSelector.clear();
- _taskByTypeExecCountAndTimestamps.clear();
- _tasksVariables.clear();
- _variablesInitialized = false;
- }
- }
- /**
- * Check if task queue main thread is running.
- *
- * @return
- */
- public boolean isTaskQueueRunning()
- {
- return _taskQueueThread != null;
- }
- //===================================================== MAIN BODY =====================================================
- /* =================================== TaskQueueProc access methods ============================================= */
- public boolean validateTask(AbstractAITask task)
- {
- return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.validateTask(this, task);
- }
- public boolean checkTaskRemove(AbstractAITask task)
- {
- return tqp.checkTaskRemove(this, task);
- }
- public boolean checkTaskUpdate(AbstractAITask task)
- {
- return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.checkTaskUpdate(this, task);
- }
- /**
- * Calls queue proc, to perform task list validation. See {@link TaskQueueProc#validateQueueTasks(AI_TaskQueue)}.
- *
- * @return
- */
- public boolean validateQueueTasks()
- {
- return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.validateQueueTasks(this);
- }
- /* ================================ TaskQueue variables initialization and access / support methods =========================== */
- public void initDefaultTasksVariables()
- {
- // first run after construction: init task queue variables
- if (_variablesInitialized)
- return;
- _variablesInitialized = true;
- boolean allOk = false;
- try
- {
- allOk = registerTaskVariable(new AITaskSimpleVar(this, "_taskExecCounter", (long)0, (long)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecTimestamp", (long)0, (long)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecId", (int)0, (int)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecHashCode", (int)0, (int)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateId", (int)0, (int)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateHashCode", (int)0, (int)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateTimestamp", (long)0, (long)0));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_taskUpdateCounter", (long)0, (long)0));
- /*allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_actorTarget", (L2Object)null, (L2Object)null));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiAtkTarget", (L2Character)null, (L2Character)null));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiFollowTarget", (L2Character)null, (L2Character)null));
- allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiCastTarget", (L2Character)null, (L2Character)null));*/
- /** ------------------------ see {@link TaskQueueProc#initTaskVariables(AI_TaskQueue)} ------------------------- */
- allOk &= tqp.initTaskVariables(this);
- }
- catch (Exception e)
- {
- _log.log(Level.SEVERE, this.getClass().getSimpleName() + " [" + getTaskQueueName() + "] initDefaultTasksVariables failed with error: " + e.getMessage(), e);
- }
- if (!allOk && getActor().isAIDebug() && Config.AI_log_this(getActor(), "task_queue_init_vars"))
- _log.log(Level.WARNING, this.getClass().getSimpleName() + " [" + getTaskQueueName() + "] initDefaultTasksVariables failed registering all Task Queue variables.");
- }
- /**
- * Register new AITaskVariable for queue, accesible from eg. tasks themselves.
- *
- * @param var
- *
- * @return
- */
- public boolean registerTaskVariable(AITaskSimpleVar var)
- {
- return var != null && _tasksVariables.putIfAbsent(var.getVarName(), var) == null;
- }
- /**
- * Unregister variable.
- *
- * @param varName
- *
- * @return
- */
- public boolean unregisterTaskVariable(String varName)
- {
- return _tasksVariables.remove(varName) != null;
- }
- /**
- * Check if variable with specified name exists.
- *
- * @param varName
- *
- * @return
- */
- public boolean hasTaskVariable(String varName)
- {
- return getTaskVariable(varName) != null;
- }
- public AITaskSimpleVar getTaskVariable(String varName)
- {
- return _tasksVariables.get(varName);
- }
- public boolean setTaskVariableValue(String varName, Object value)
- {
- return hasTaskVariable(varName) && setTaskVariableValue(varName, value, false, true);
- }
- public boolean setTaskVariableValue(String varName, Object value, boolean force)
- {
- return hasTaskVariable(varName) && setTaskVariableValue(varName, value, false, force);
- }
- public boolean setTaskVariableValue(String varName, Object value, boolean initial, boolean force)
- {
- return hasTaskVariable(varName) && getTaskVariable(varName).setValue(value, initial, force);
- }
- public Object getTaskVariableValue(String varName)
- {
- return getTaskVariableValue(varName, false);
- }
- public Object getTaskVariableValue(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return null;
- return getTaskVariable(varName).getValue(initial);
- }
- public int getTaskVariableValueInt(String varName)
- {
- return getTaskVariableValueInt(varName, false);
- }
- public int getTaskVariableValueInt(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return Integer.MAX_VALUE;
- return ((Number)getTaskVariableValue(varName, initial)).intValue();
- }
- public long getTaskVariableValueLong(String varName)
- {
- return getTaskVariableValueLong(varName, false);
- }
- public long getTaskVariableValueLong(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return Long.MAX_VALUE;
- return ((Number)getTaskVariableValue(varName, initial)).longValue();
- }
- public double getTaskVariableValueDouble(String varName)
- {
- return getTaskVariableValueDouble(varName, false);
- }
- public double getTaskVariableValueDouble(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return Double.MAX_VALUE;
- return ((Number)getTaskVariableValue(varName, initial)).doubleValue();
- }
- public String getTaskVariableValueString(String varName)
- {
- return getTaskVariableValueString(varName, false);
- }
- public String getTaskVariableValueString(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return null;
- return ((String)getTaskVariableValue(varName, initial));
- }
- public boolean getTaskVariableValueBool(String varName)
- {
- return getTaskVariableValueBool(varName, false);
- }
- public boolean getTaskVariableValueBool(String varName, boolean initial)
- {
- if (!hasTaskVariable(varName))
- return false;
- return ((Boolean)getTaskVariableValue(varName, initial));
- }
- /* =========================================== Other methods =============================================== */
- /**
- * Get this TaskQueue name (for debug purposes).
- *
- * @return
- */
- public String getTaskQueueName()
- {
- if (_taskQueueName != null)
- return _taskQueueName;
- return "AI_TaskQueue";
- }
- /**
- * Change TaskQueue name, used for identyfing while debugging.
- *
- * @param _taskQueueName
- */
- public void setTaskQueueName(String _taskQueueName)
- {
- this._taskQueueName = _taskQueueName;
- }
- /**
- * Check if specified task instance is queued by AI.
- *
- * @param task
- *
- * @return
- */
- public boolean isTaskQueued(AbstractAITask task)
- {
- return _queuedTasks.contains(task);
- }
- /**
- * Check if there is already queued other task instance of the same type (comparing hashCode() method result, not task ids).
- *
- * @param task
- *
- * @return
- */
- public boolean isTaskOfTypeQueued(AbstractAITask task)
- {
- return isTaskQueued(task) || countTaskOfTypeInQueue(task.hashCode()) > 0;
- }
- /**
- * Remove specified task (by task id), from AI task queue.
- *
- * @param task
- * @param releaseId when true, task's id will be released in server core IdFactory, returning id to the pool. After releasing Id, you need to use task.getNewId() to assign new Id to a task, if you wish to queue/use it again.
- *
- * @return true when task was sucessfully removed, false when task not found (not queued).
- */
- public boolean removeTaskFromQueue(AbstractAITask task, boolean releaseId)
- {
- if (!isTaskQueued(task))
- {
- if (releaseId && !task.released())
- task.free();
- return false;
- }
- // boolean locked = _lock.isLocked();
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- // _lock.lock();
- if (!_lock.tryLock())
- return false;
- try
- {
- task.on_remove_from_queue(this);
- _queuedTasks.remove(task);
- if (task.random())
- _rndTaskSelector.remove(task);
- if (releaseId && !task.released())
- task.free();
- return true;
- }
- finally
- {
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- _lock.unlock();
- }
- }
- /**
- * Process random task "weight" updating procedure.
- *
- * @param task
- *
- * @return true if successfully updated. False when task is not of "random" type, is invalid, not queued, or weight didn't changed.
- */
- protected boolean updateRandomTaskWeight(AbstractAITask task)
- {
- if (!isTaskQueued(task) || !checkTaskUpdate(task))
- return false;
- if (!_lock.tryLock())
- return false;
- try
- {
- int w = task.update_weight();
- if (w > 0 && w != task.weight(false))
- {
- // boolean locked = _lock.isLocked();
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- // _lock.lock();
- // try
- // {
- _rndTaskSelector.tryUpdateTask(task, w);
- task.setWeight(w, false);
- _rndTaskSelector.addIfAbsent(task, true);
- setTaskVariableValue("_lastTaskUpdateId", task.getTaskId());
- setTaskVariableValue("_lastTaskUpdateHashCode", task.hashCode());
- setTaskVariableValue("_lastTaskUpdateTimestamp", System.currentTimeMillis());
- long c = getTaskVariableValueLong("_taskUpdateCounter") + 1;
- setTaskVariableValue("_taskUpdateCounter", c);
- return true;
- // }
- // finally
- // {
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- // _lock.unlock();
- // }
- }
- }
- finally
- {
- _lock.unlock();
- }
- return false;
- }
- /**
- * Perform manual tasks weights update and rnd task selector reset.
- *
- * @return
- */
- public boolean updateRndSelectorAndTasksWeights()
- {
- return _rndTaskSelector.updateAllTasksAndWeights();
- }
- /**
- * Add new task to execution queue.
- *
- * @param task
- * @param topOfQueue true - task will be added at the queue top (will be first executed/processed with next queue cycle, before all other already added, or added at the end)
- *
- * @return true when task was sucessfully added to queue.
- */
- public boolean addTaskToQueue(AbstractAITask task, boolean topOfQueue)
- {
- if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
- return false;
- if (!isTaskQueued(task) && canAddTaskToQueue(task))
- {
- // boolean locked = _lock.isLocked();
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- // _lock.lock();
- if (!_lock.tryLock())
- return false;
- try
- {
- task.setTaskQueue(this);
- if (task.released())
- task.getNewId();
- task.setAddedOnTaskRunCycle(getTaskRunCycle());
- if (task.random())
- _rndTaskSelector.addIfAbsent(task, true);
- if (topOfQueue)
- _queuedTasks.addFirst(task);
- else
- _queuedTasks.add(task);
- task.on_added_to_queue(this);
- return true;
- }
- finally
- {
- // if (Config.AI_TASK_QUEUE_LOCKING && !locked)
- _lock.unlock();
- }
- }
- return false;
- }
- /**
- * Cancel all tasks, remove from queue, and release all Id's.
- */
- public void clearTaskQueue()
- {
- for (AbstractAITask t : _queuedTasks)
- {
- if (t != null)
- t.removeFromQueue(true);
- }
- }
- /**
- * Method processess all queued tasks, and performs removal of invalid/outdated tasks, updates "random" tasks weights etc. Should be executed before performing cycle of executing tasks.
- *
- * @return debug info, when removed/updated any task, or empty sting when nothing happened.
- */
- private String processTasks()
- {
- int removed = 0;
- int updated = 0;
- ListIterator<AbstractAITask> i = _queuedTasks.listIterator();
- AbstractAITask task;
- while (i.hasNext())
- {
- task = i.next();
- if (task == null)
- {
- i.remove();
- continue;
- }
- if (checkTaskRemove(task)) // check if it's invalid task, ready for removal
- {
- task.on_remove_from_queue(this);
- i.remove(); // remove task.
- if (task.random()) // if it's "random" task, remove also from random generator
- _rndTaskSelector.remove(task);
- if (!task.released()) // release task's id from IdFactory, if not released
- task.free();
- removed++;
- continue;
- }
- if (checkTaskUpdate(task) && updateRandomTaskWeight(task)) // check if task is ready to be executed?
- updated++;
- }
- return removed > 0 || updated > 0 ? "procAITasks \n<font color=99ff99>" + getTaskQueueName() + "</font>\nremoved: " + removed + "\nupdated: " + updated : "";
- }
- /**
- * Run task.
- *
- * @param task
- *
- * @return 0 - execution ok, do nothing, -1 - execution failed, remove task from queue, -2 - other error (task null??), 1 - execution failed/rescheduled, move task to queue top (for next cycle), and go to next task,
- * 2 - (for random type tasks only): execution not performed, instead performed task weight update, -3 - not executed task
- */
- public int runTask(AbstractAITask task)
- {
- int res = 0;
- String taskExecDebugMsg = "ai_task_exec \n<font color=99ff99>" + getTaskQueueName() + "</font>\nType: <font color=999999>$taskClassName</font>\nId: $taskId\n$infoMsg";
- int debugtype = 3; // 0 - info, 1 - warning, 2 - error;
- if (task != null)
- {
- String infoMsg = "";
- debugtype = 2;
- if (task.runThread())
- {
- setTaskVariableValue("_lastTaskExecId", task.getTaskId());
- setTaskVariableValue("_lastTaskExecHashCode", task.hashCode());
- long c = getTaskVariableValueLong("_taskExecCounter") + 1;
- setTaskVariableValue("_taskExecCounter", c);
- setTaskVariableValue("_lastTaskExecTimestamp", System.currentTimeMillis());
- debugtype = 0;
- infoMsg += "executed";
- infoMsg += ", execOk(" + task.execSuccess() + ")";
- if (!task.execSuccess())
- debugtype = 1;
- else
- {
- res = 0;
- if (task.block_think_after_run() && _performThinkTask)
- {
- _lastAIThreadRunCycle = getAI().getMainThreadRunCycle();
- _performThinkTask = false;
- }
- }
- if (task.removeable())
- {
- infoMsg += ", removed";
- res = -1;
- }
- else
- {
- if (!task.cyclic())
- {
- infoMsg += ", resetted";
- task.reset();
- }
- if (!task.random() && !task.cyclic())
- {
- infoMsg += ", reAdded";
- res = 1;
- }
- else if (task.random())
- {
- infoMsg += ", weightUpdated";
- res = 2;
- }
- }
- }
- else
- {
- infoMsg += "!executed";
- res = -3;
- }
- String dbgType = "";
- switch (debugtype)
- {
- case 0:
- dbgType = "_info";
- break;
- case 1:
- dbgType = "_warning";
- break;
- case 2:
- dbgType = "_error";
- break;
- }
- if (getActor().isAIDebug() && (Config.AI_log_this(getActor(), "ai_task_exec") || Config.AI_log_this(getActor(), "ai_task_exec" + dbgType) || (Config.AI_log_this(getActor(), "ai_task_" + task.getTaskTypeName()))) && !(task.quiet_exec()))
- {
- taskExecDebugMsg = taskExecDebugMsg.replace("$taskClassName", task.getTaskTypeName());
- taskExecDebugMsg = taskExecDebugMsg.replace("$taskId", String.valueOf(task.getTaskId()));
- taskExecDebugMsg = taskExecDebugMsg.replace("$infoMsg", infoMsg);
- try
- {
- switch (debugtype)
- {
- case 0:
- getAI().getAccessor().debug().debugRegisterActorAI_Info(taskExecDebugMsg);
- break;
- case 1:
- getAI().getAccessor().debug().debugRegisterActorAI_Warning(taskExecDebugMsg);
- break;
- case 2:
- getAI().getAccessor().debug().debugRegisterActorAI_Error(taskExecDebugMsg);
- break;
- }
- String trace = getAI().getAccessor().debug().executionTrace();
- if (trace != null)
- getAI().getAccessor().debug().getEventsAndIntentionsHistory().putIfAbsent(System.currentTimeMillis(), "<br1>- " + trace);
- }
- catch (Exception e)
- {
- }
- }
- }
- else
- res = -2;
- return res;
- }
- protected boolean execTasksFromQueue(boolean onlyCyclic)
- {
- if (_executingQueueTask || _queuedTasks.isEmpty())
- return false;
- _executingQueueTask = true;
- int removed = 0;
- int executed = 0;
- int updated = 0;
- boolean abort = false;
- try
- {
- for (AbstractAITask task : _queuedTasks)
- {
- if (abort)
- break;
- if (task != null && !task.random() && task.cyclic() == onlyCyclic && validateTask(task))
- {
- int result = runTask(task);
- switch (result)
- {
- case -3:
- // Not executed
- break;
- case -2:
- // NPE
- break;
- case -1:
- // if (checkTaskRemove(task) && task.removeFromQueue(true))
- // removed++;
- executed++;
- abort = !onlyCyclic;
- break;
- case 0:
- // OK
- executed++;
- abort = !onlyCyclic;
- break;
- case 1: // only for not cyclic and not random tasks.
- // _lock.lock();
- // try
- {
- _queuedTasks.remove(task); // remove task.
- _queuedTasks.addFirst(task); // readd at queue top
- }
- // finally
- // {
- // _lock.unlock();
- // }
- executed++;
- abort = !onlyCyclic;
- break;
- case 2: // cyclic / random task updated weight after exec.
- // if (checkTaskUpdate(task) && updateRandomTaskWeight(task))
- // updated++;
- executed++;
- abort = !onlyCyclic;
- break;
- }
- }
- }
- }
- catch (Exception e)
- {
- _log.log(Level.WARNING, "AI " + (onlyCyclic ? "Cyclic" : "") + "TaskExecution exception: " + e.getMessage(), e);
- }
- finally
- {
- _executingQueueTask = false;
- }
- return executed > 0;
- }
- public int getRandomTasksQueueSize()
- {
- return _rndTaskSelector.size();
- }
- protected boolean execNextRandomTaskFromQueue()
- {
- if (_executingQueueTask || _queuedTasks.isEmpty())
- return false;
- _executingQueueTask = true;
- try
- {
- _rndTaskSelector.reset();
- int maxRndCycles = getRandomTasksQueueSize();
- while (_rndTaskSelector.hasNext() && maxRndCycles > 0)
- {
- AbstractAITask rndTask = _rndTaskSelector.next(true);
- maxRndCycles--;
- if (!validateTask(rndTask))
- continue;
- int result = runTask(rndTask);
- switch (result)
- {
- case -3:
- // Not executed
- break;
- case -2:
- // NPE
- break;
- case -1:
- // if (checkTaskRemove(rndTask))
- // rndTask.removeFromQueue(true); // remove task.
- return true;
- case 0:
- // OK
- return true;
- case 2: // cyclic / random task updated weight after exec.
- return true;//checkTaskUpdate(rndTask) && updateRandomTaskWeight(rndTask);
- }
- }
- }
- catch (Exception e)
- {
- _log.log(Level.WARNING, "AI RandomTaskExecution exception: " + e.getMessage(), e);
- }
- finally
- {
- _executingQueueTask = false;
- }
- return false;
- }
- /**
- * Returns AI TaskQueue debug info (list of tasks and statuses).
- *
- * @return
- */
- public String getTaskQueueInfo()
- {
- if (_queuedTasks.isEmpty())
- return ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nTask Queue [" + getTaskQueueName() + "] is empty.\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
- String r = ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nAI Task Queue [" + getTaskQueueName() + "]\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
- int tNum = 1;
- for (AbstractAITask t : _queuedTasks)
- {
- r += "\n" + tNum + ") " + t.getTaskTypeName() + " " + t.toString(true).replace(" ", "\n - ") + (tNum < _queuedTasks.size() ? "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_C) : "");
- tNum++;
- }
- r += "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
- return r;
- }
- public String getVariablesInfo()
- {
- String r = ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nTask Queue Variables\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
- int num = 1;
- for (AITaskSimpleVar v : _tasksVariables.values())
- {
- r += "\n" + (num > 1 ? ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_C) + "\n" : "") + num + ") " + v;
- num++;
- }
- r += "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
- return r;
- }
- /**
- * Returns number of tasks of certain class name, currently queued.
- *
- * @param taskClassName
- *
- * @return
- */
- public int countTaskOfTypeInQueue(String taskClassName)
- {
- if (taskClassName == null || taskClassName.isEmpty())
- return 0;
- return countTaskOfTypeInQueue(taskClassName.hashCode());
- }
- /**
- * Returns number of tasks of certain class name, currently queued.
- *
- * @param hashCode
- *
- * @return
- */
- public int countTaskOfTypeInQueue(int hashCode)
- {
- if (_queuedTasks.isEmpty())
- return 0;
- int c = 0;
- for (AbstractAITask t : _queuedTasks)
- {
- if (t != null && !checkTaskRemove(t) && t.hashCode() == hashCode)
- c++;
- }
- return c;
- }
- /**
- * Returns queued task object, that unique task id or hashCode equals taskIdOrHashCode. There can be only 1 task with certain id, while all tasks of same type, share same hashCode(). Use this
- * method to get certain types of tasks when needed.
- *
- * @param taskIdOrHashCode
- *
- * @return
- */
- public FastList<AbstractAITask> getQueuedTasks(int taskIdOrHashCode)
- {
- FastList<AbstractAITask> tasks = new FastList<AbstractAITask>();
- if (_queuedTasks.isEmpty())
- return tasks;
- for (AbstractAITask t : _queuedTasks)
- {
- if (t != null && !t.removeable() && ((!t.released() && t.getTaskId() == taskIdOrHashCode) || t.hashCode() == taskIdOrHashCode))
- tasks.add(t);
- }
- return tasks;
- }
- /**
- * @param hashCode
- *
- * @return true if at least one task with that hashCode currently in tasks queue.
- */
- public boolean hasTaskOfTypeInQueue(int hashCode)
- {
- return countTaskOfTypeInQueue(hashCode) > 0;
- }
- /**
- * @param taskClassName
- *
- * @return true if at least one task with taskClassName currently in tasks queue.
- */
- public boolean hasTaskOfTypeInQueue(String taskClassName)
- {
- return countTaskOfTypeInQueue(taskClassName) > 0;
- }
- /**
- * Validates task's conditions, if it can be queued.
- *
- * @param task
- *
- * @return
- */
- public boolean canAddTaskToQueue(AbstractAITask task)
- {
- if (!task.valid())
- return false;
- if (task.max_task_instances() < 0)
- return true;
- if (task.max_task_instances() == 0)
- return false;
- return countTaskOfTypeInQueue(task.hashCode()) < task.max_task_instances();
- }
- /**
- * Executed from within a task, to register global execution count of certain task type.
- *
- * @param task
- */
- public void registerTaskTypeExecCountAndTimestamp(AbstractAITask task)
- {
- registerTaskTypeExecCountAndTimestamp(task.hashCode());
- }
- /**
- * Executed from within a task, to register global execution count of certain task type.
- *
- * @param taskTypeHashCode
- */
- public void registerTaskTypeExecCountAndTimestamp(int taskTypeHashCode)
- {
- // Object tte = getTaskVariableValue("_tte_counters_"+taskTypeHashCode);
- Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
- if (t == null || t.length < 2)
- {
- t = new Long[2];
- t[1] = 0L;
- }
- t[0] = System.currentTimeMillis();
- t[1]++;
- _taskByTypeExecCountAndTimestamps.put(taskTypeHashCode, t);
- }
- public int getTaskTypeExecCount(AbstractAITask task)
- {
- return getTaskTypeExecCount(task.hashCode());
- }
- public int getTaskTypeExecCount(int taskTypeHashCode)
- {
- Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
- if (t == null || t.length < 2)
- return 0;
- return t[1].intValue();
- }
- public long getTaskTypeLastExecTimestamp(AbstractAITask task)
- {
- return getTaskTypeLastExecTimestamp(task.hashCode());
- }
- public long getTaskTypeLastExecTimestamp(int taskTypeHashCode)
- {
- Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
- if (t == null || t.length < 2)
- return 0;
- return t[0];
- }
- /**
- * Access list of queued tasks.
- *
- * @return
- */
- public Collection<AbstractAITask> getQueuedTasks()
- {
- return _queuedTasks;
- }
- /**
- * Detemine if any task locked think task execution for one AI thread cycle. See {@link #resetThinkTaskBlock()}.
- *
- * @return
- */
- public boolean isPerformThinkTask()
- {
- return _performThinkTask;
- }
- /**
- * Lifts EVT_THINK blockade for AI process, put by one of tasks, that request to skipp "think" cycle after execution.
- */
- public void resetThinkTaskBlock()
- {
- _performThinkTask = true;
- }
- private int _taskRunCounter = 0, _taskRunCycle = 0;
- private long _validateQueueRunTs = 0;
- private int _lastAIThreadRunCycle = 0;
- /**
- * Resturns number of task run cycle, if task queue is running, or -1 if not. Task run cycle counter is used, to enforce tasks to wait and not be ran, for certain
- * reasons (eg. just after adding task, most will wait for first execution try, for next task run cycle). See {@link AbstractAITask#waiting(int taskRunCycle)}. To
- * determine, if queue is running, see {@link #isTaskQueueRunning()}
- *
- * @return
- */
- public int getTaskRunCycle()
- {
- return isTaskQueueRunning() ? _taskRunCycle : -1;
- }
- private int execNextRandomTaskCounter = 0;
- private boolean runCleanup = false;
- @Override
- public void run()
- {
- if (GameServer.serverStartingUp || _taskQueueThread == null || (hasAI() && getAI().isThrowedAndFlying()))
- return;
- if (!hasAI())
- {
- stopTaskQueue();
- return;
- }
- // boolean unlock = false;
- // if (Config.AI_TASK_QUEUE_LOCKING)
- // {
- // unlock = _lock.tryLock();
- // if (!unlock)
- // return;
- // }
- try
- {
- _taskRunCounter++;
- if (_taskRunCounter % 3 == 0 || _taskRunCounter % 4 == 0)
- {
- _taskRunCycle++;
- if (getAI().getMainThreadRunCycle() < 0 || _lastAIThreadRunCycle < getAI().getMainThreadRunCycle())
- _performThinkTask = true;
- if (_taskRunCounter % 4 == 0)
- {
- // try exec random task
- if (!execTasksFromQueue(false))
- {
- // when failed do not always try executing other random task, as the 2nd method performs task randomizer reset!
- execNextRandomTaskCounter++;
- if (execNextRandomTaskCounter > 1)
- {
- execNextRandomTaskCounter = 0;
- execNextRandomTaskFromQueue();
- }
- }
- }
- else // exec cyclic tasks
- execTasksFromQueue(true);
- }
- else if (_validateQueueRunTs <= 0 || System.currentTimeMillis() - _validateQueueRunTs > 1000)
- {
- _validateQueueRunTs = System.currentTimeMillis();
- if (runCleanup)
- {
- /* ================= PROCESS TASKS (VALIDATE AND CLEAN QUEUE), PERFORM UPDATES, EXECUTE GENERAL TASKS, FROM TOP OF THE QUEUE, TO BOTTOM ================ */
- String prcDebug = processTasks();
- if (!prcDebug.isEmpty() && getActor().isAIDebug() && Config.AI_log_this(getActor(), "proc_ai_tasks"))
- {
- try {getAI().getAccessor().debug().debugRegisterActorAI_Info(prcDebug); }
- catch (Exception e) { }
- }
- /* ================= CHOOSE 1 RANDOM TASK FROM RANDOM TASKS, BY IT'S CURRENT WEIGHT LEVEL, AND TRY TO EXECUTE / PERFORM UPDATE ================ */
- }
- else
- validateQueueTasks();
- runCleanup = !runCleanup;
- }
- }
- catch (Exception e)
- {
- _log.log(Level.WARNING, this + ": Exception " + e.getMessage(), e);
- }
- // finally
- // {
- // if (unlock)
- // _lock.unlock();
- // }
- }
- /**
- * Used to manually execute and process tasks on queue. If tast queue is running, this method will abort and always return false.
- *
- * @return
- */
- public boolean execTasksQueue()
- {
- if (isTaskQueueRunning())
- return false;
- /* ================= PROCESS TASKS (VALIDATE AND CLEAN QUEUE), PERFORM UPDATES, EXECUTE GENERAL TASKS, FROM TOP OF THE QUEUE, TO BOTTOM ================ */
- String prcDebug = processTasks();
- if (!prcDebug.isEmpty() && getActor().isAIDebug() && Config.AI_log_this(getActor(), "proc_ai_tasks"))
- {
- try { getAI().getAccessor().debug().debugRegisterActorAI_Info(prcDebug); } catch (Exception e) { }
- }
- /* ================= CHOOSE 1 RANDOM TASK FROM RANDOM TASKS, BY IT'S CURRENT WEIGHT LEVEL, AND TRY TO EXECUTE / PERFORM UPDATE ================ */
- _performThinkTask = true;
- boolean executed = false;
- executed |= execTasksFromQueue(false);
- if (!executed)
- executed |= execNextRandomTaskFromQueue();
- executed |= execTasksFromQueue(true);
- return executed;
- }
- /**
- * Tries to execute task (from current queue), by specified class name.
- *
- * @param taskClassName name of task class to execute
- *
- * @return true on success, false when execution is not allowed, or task of that class is not on current task queue.
- */
- public boolean runTaskOfType(String taskClassName)
- {
- return runTaskOfType(taskClassName.hashCode());
- }
- /**
- * Tries to execute task (from current queue), by specified hashCode.
- *
- * @param hashCodeOrTaskId hashCode of task to execute
- *
- * @return true on success, false when execution is not allowed, or task of that hash code not in queue.
- */
- public boolean runTaskOfType(int hashCodeOrTaskId)
- {
- FastList<AbstractAITask> tasks = getQueuedTasks(hashCodeOrTaskId);
- if (tasks.isEmpty())
- return false;
- AbstractAITask task = null;
- if (tasks.size() == 1)
- task = tasks.getFirst();
- else
- {
- RndTaskSelector selector = new RndTaskSelector(tasks);
- while (selector.hasNext())
- {
- task = selector.next(true);
- if (task.valid())
- break;
- else
- task = null;
- }
- }
- if (task != null && validateTask(task))
- {
- int result = runTask(task);
- switch (result)
- {
- case -3:
- // Not executed
- return false;
- case -2:
- // NPE
- return false;
- case -1:
- return true;
- case 0:
- // OK
- return true;
- case 2: // cyclic / random task updated weight after exec.
- return true;//checkTaskUpdate(rndTask) && updateRandomTaskWeight(rndTask);
- }
- }
- return false;
- }
- public ITaskQueueController getController()
- {
- return _controller;
- }
- public void setController(final ITaskQueueController controller)
- {
- _controller = controller;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement