Advertisement
Deedlit

ai task queue

Aug 23rd, 2021
1,126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 35.62 KB | None | 0 0
  1. /*
  2.  * This program is free software: you can redistribute it and/or modify it under
  3.  * the terms of the GNU General Public License as published by the Free Software
  4.  * Foundation, either version 3 of the License, or (at your option) any later
  5.  * version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful, but WITHOUT
  8.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9.  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10.  * details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License along with
  13.  * this program. If not, see <http://www.gnu.org/licenses/>.
  14.  */
  15. package com.l2jserver.gameserver.ai.ext;
  16.  
  17. import com.l2jserver.Config;
  18. import com.l2jserver.gameserver.GameServer;
  19. import com.l2jserver.gameserver.ThreadPoolManager;
  20. import com.l2jserver.gameserver.ai.ext.struct.task.AITaskSimpleVar;
  21. import com.l2jserver.gameserver.ai.ext.tasks.AbstractAITask;
  22. import com.l2jserver.gameserver.ai.ext.tasks.interfaces.TaskQueueProc;
  23. import com.l2jserver.gameserver.ai.ext.tasks.util.RndTaskSelector;
  24. import com.l2jserver.gameserver.ext.util.ExtUtil;
  25. import com.l2jserver.gameserver.model.actor.L2Character;
  26. import com.l2jserver.gameserver.model.interfaces.ITaskQueueController;
  27. import com.l2jserver.util.Rnd;
  28. import javolution.util.FastComparator;
  29. import javolution.util.FastList;
  30. import javolution.util.FastMap;
  31.  
  32. import java.util.Collection;
  33. import java.util.ListIterator;
  34. import java.util.concurrent.ScheduledFuture;
  35. import java.util.concurrent.locks.ReentrantLock;
  36. import java.util.logging.Level;
  37. import java.util.logging.Logger;
  38.  
  39. /**
  40.  * ==============================================<br>
  41.  * AI TaskQueue - MMOPlay project AI TaskQueue extension.<br>
  42.  * ==============================================<br>
  43.  *
  44.  * @author Deedlit(deedlit @ protonmail.com)
  45.  * @version 1.7.9.91
  46.  */
  47. public class AI_TaskQueue extends AI_AbstractHelper implements Runnable
  48. {
  49.     public static final Logger _log = Logger.getLogger("AI_TaskQueue");
  50.  
  51.     /* ------------------ AI queued tasks holders ---------------------------- */
  52.     private FastList<AbstractAITask> _queuedTasks = new FastList<AbstractAITask>().shared();
  53.     private RndTaskSelector _rndTaskSelector = new RndTaskSelector();
  54.  
  55.     /* ------------------ Task execution data holders ---------------------------- */
  56.     private FastMap<Integer, Long[]> _taskByTypeExecCountAndTimestamps = new FastMap<Integer, Long[]>().shared();
  57.  
  58.     /* ------------------ Other fields ---------------------------- */
  59.     private int taskIntervalMs = 100;
  60.     private String _taskQueueName = "AI_TaskQueue";
  61.     private volatile boolean _executingQueueTask = false;
  62.     private ScheduledFuture<?> _taskQueueThread = null;
  63.     private volatile boolean _performThinkTask = true;
  64.     private boolean _variablesInitialized = false;
  65.     private ReentrantLock _lock = new ReentrantLock(true);
  66.  
  67.     /* ------------------ Task variables map ---------------------------- */
  68.     private FastMap<String, AITaskSimpleVar> _tasksVariables;
  69.  
  70.     /* ------------------- Task queue proc. interface for processing task queue tasks, depending on where queue is used (character AI, formation AI, zone AI, player AI etc...) ------------------ */
  71.     private TaskQueueProc tqp;
  72.     private ITaskQueueController _controller;
  73.  
  74.     //===================================================== CONSTRUCTORS =====================================================
  75.  
  76.     /**
  77.      * @param controller
  78.      * @param taskQueueName
  79.      * @param tqp
  80.      * @param taskIntervalMs
  81.      */
  82.     public AI_TaskQueue(ITaskQueueController controller, String taskQueueName, TaskQueueProc tqp, int taskIntervalMs)
  83.     {
  84.         super(controller.getController() instanceof L2Character ? ((L2Character)controller.getController()) : null);
  85.         _controller = controller;
  86.         _taskQueueName = taskQueueName;
  87.         this.tqp = tqp;
  88.         if (taskIntervalMs >= 50)
  89.             this.taskIntervalMs = taskIntervalMs;
  90.  
  91.         _tasksVariables = new FastMap<String, AITaskSimpleVar>().shared();
  92.  
  93.         // initialize task queue internal variables
  94.         initDefaultTasksVariables();
  95.     }
  96.  
  97.     //===================================================== MAIN BODY =====================================================
  98.  
  99.     /**
  100.      * Start task queue main thread.
  101.      */
  102.     public synchronized void startTaskQueue()
  103.     {
  104.         runCleanup = false;
  105.         execNextRandomTaskCounter = 0;
  106. //      setLockingEnabled(Config.AI_TASK_QUEUE_LOCKING);
  107.         if (_taskQueueThread == null)
  108.         {
  109.             _taskQueueThread = Config.AI_TASK_QUEUE_USE_THREAD_POOL_EXECUTOR ? ThreadPoolManager.getInstance().scheduleAiTaskAtFixedRate(this, Rnd.qget(200, 750), taskIntervalMs) :
  110.                     ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(this, Rnd.qget(200, 750), taskIntervalMs);
  111.             initDefaultTasksVariables();
  112.         }
  113.     }
  114.  
  115.     /**
  116.      * Stop task queue main thread.
  117.      */
  118.     public synchronized void stopTaskQueue()
  119.     {
  120.         if (_taskQueueThread != null)
  121.         {
  122.             _performThinkTask = true;
  123.             _taskQueueThread.cancel(false);
  124.             _taskQueueThread = null;
  125. //          _queuedTasks.clear();
  126. //          _rndTaskSelector.clear();
  127.             _taskByTypeExecCountAndTimestamps.clear();
  128.             _tasksVariables.clear();
  129.             _variablesInitialized = false;
  130.         }
  131.     }
  132.  
  133.     /**
  134.      * Check if task queue main thread is running.
  135.      *
  136.      * @return
  137.      */
  138.     public boolean isTaskQueueRunning()
  139.     {
  140.         return _taskQueueThread != null;
  141.     }
  142.  
  143.  
  144.     //===================================================== MAIN BODY =====================================================
  145.  
  146.  
  147.     /* =================================== TaskQueueProc access methods ============================================= */
  148.  
  149.     public boolean validateTask(AbstractAITask task)
  150.     {
  151.         return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.validateTask(this, task);
  152.     }
  153.  
  154.     public boolean checkTaskRemove(AbstractAITask task)
  155.     {
  156.         return tqp.checkTaskRemove(this, task);
  157.     }
  158.  
  159.     public boolean checkTaskUpdate(AbstractAITask task)
  160.     {
  161.         return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.checkTaskUpdate(this, task);
  162.     }
  163.  
  164.     /**
  165.      * Calls queue proc, to perform task list validation. See {@link TaskQueueProc#validateQueueTasks(AI_TaskQueue)}.
  166.      *
  167.      * @return
  168.      */
  169.     public boolean validateQueueTasks()
  170.     {
  171.         return !(GameServer.serverStartingUp || GameServer.serverShuttingDown) && tqp.validateQueueTasks(this);
  172.     }
  173.  
  174.     /* ================================ TaskQueue variables initialization and access / support methods =========================== */
  175.  
  176.     public void initDefaultTasksVariables()
  177.     {
  178.         // first run after construction: init task queue variables
  179.         if (_variablesInitialized)
  180.             return;
  181.         _variablesInitialized = true;
  182.  
  183.         boolean allOk = false;
  184.         try
  185.         {
  186.             allOk = registerTaskVariable(new AITaskSimpleVar(this, "_taskExecCounter", (long)0, (long)0));
  187.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecTimestamp", (long)0, (long)0));
  188.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecId", (int)0, (int)0));
  189.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskExecHashCode", (int)0, (int)0));
  190.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateId", (int)0, (int)0));
  191.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateHashCode", (int)0, (int)0));
  192.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_lastTaskUpdateTimestamp", (long)0, (long)0));
  193.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_taskUpdateCounter", (long)0, (long)0));
  194.  
  195.             /*allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_actorTarget", (L2Object)null, (L2Object)null));
  196.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiAtkTarget", (L2Character)null, (L2Character)null));
  197.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiFollowTarget", (L2Character)null, (L2Character)null));
  198.             allOk &= registerTaskVariable(new AITaskSimpleVar(this, "_aiCastTarget", (L2Character)null, (L2Character)null));*/
  199.  
  200.             /** ------------------------ see {@link TaskQueueProc#initTaskVariables(AI_TaskQueue)} ------------------------- */
  201.             allOk &= tqp.initTaskVariables(this);
  202.         }
  203.         catch (Exception e)
  204.         {
  205.             _log.log(Level.SEVERE, this.getClass().getSimpleName() + " [" + getTaskQueueName() + "] initDefaultTasksVariables failed with error: " + e.getMessage(), e);
  206.         }
  207.  
  208.         if (!allOk && getActor().isAIDebug() && Config.AI_log_this(getActor(), "task_queue_init_vars"))
  209.             _log.log(Level.WARNING, this.getClass().getSimpleName() + " [" + getTaskQueueName() + "] initDefaultTasksVariables failed registering all Task Queue variables.");
  210.     }
  211.  
  212.     /**
  213.      * Register new AITaskVariable for queue, accesible from eg. tasks themselves.
  214.      *
  215.      * @param var
  216.      *
  217.      * @return
  218.      */
  219.     public boolean registerTaskVariable(AITaskSimpleVar var)
  220.     {
  221.         return var != null && _tasksVariables.putIfAbsent(var.getVarName(), var) == null;
  222.     }
  223.  
  224.     /**
  225.      * Unregister variable.
  226.      *
  227.      * @param varName
  228.      *
  229.      * @return
  230.      */
  231.     public boolean unregisterTaskVariable(String varName)
  232.     {
  233.         return _tasksVariables.remove(varName) != null;
  234.     }
  235.  
  236.     /**
  237.      * Check if variable with specified name exists.
  238.      *
  239.      * @param varName
  240.      *
  241.      * @return
  242.      */
  243.     public boolean hasTaskVariable(String varName)
  244.     {
  245.         return getTaskVariable(varName) != null;
  246.     }
  247.  
  248.     public AITaskSimpleVar getTaskVariable(String varName)
  249.     {
  250.         return _tasksVariables.get(varName);
  251.     }
  252.  
  253.     public boolean setTaskVariableValue(String varName, Object value)
  254.     {
  255.         return hasTaskVariable(varName) && setTaskVariableValue(varName, value, false, true);
  256.     }
  257.  
  258.     public boolean setTaskVariableValue(String varName, Object value, boolean force)
  259.     {
  260.         return hasTaskVariable(varName) && setTaskVariableValue(varName, value, false, force);
  261.     }
  262.  
  263.     public boolean setTaskVariableValue(String varName, Object value, boolean initial, boolean force)
  264.     {
  265.         return hasTaskVariable(varName) && getTaskVariable(varName).setValue(value, initial, force);
  266.     }
  267.  
  268.     public Object getTaskVariableValue(String varName)
  269.     {
  270.         return getTaskVariableValue(varName, false);
  271.     }
  272.  
  273.     public Object getTaskVariableValue(String varName, boolean initial)
  274.     {
  275.         if (!hasTaskVariable(varName))
  276.             return null;
  277.         return getTaskVariable(varName).getValue(initial);
  278.     }
  279.  
  280.     public int getTaskVariableValueInt(String varName)
  281.     {
  282.         return getTaskVariableValueInt(varName, false);
  283.     }
  284.  
  285.     public int getTaskVariableValueInt(String varName, boolean initial)
  286.     {
  287.         if (!hasTaskVariable(varName))
  288.             return Integer.MAX_VALUE;
  289.         return ((Number)getTaskVariableValue(varName, initial)).intValue();
  290.     }
  291.  
  292.     public long getTaskVariableValueLong(String varName)
  293.     {
  294.         return getTaskVariableValueLong(varName, false);
  295.     }
  296.  
  297.     public long getTaskVariableValueLong(String varName, boolean initial)
  298.     {
  299.         if (!hasTaskVariable(varName))
  300.             return Long.MAX_VALUE;
  301.         return ((Number)getTaskVariableValue(varName, initial)).longValue();
  302.     }
  303.  
  304.     public double getTaskVariableValueDouble(String varName)
  305.     {
  306.         return getTaskVariableValueDouble(varName, false);
  307.     }
  308.  
  309.     public double getTaskVariableValueDouble(String varName, boolean initial)
  310.     {
  311.         if (!hasTaskVariable(varName))
  312.             return Double.MAX_VALUE;
  313.         return ((Number)getTaskVariableValue(varName, initial)).doubleValue();
  314.     }
  315.  
  316.     public String getTaskVariableValueString(String varName)
  317.     {
  318.         return getTaskVariableValueString(varName, false);
  319.     }
  320.  
  321.     public String getTaskVariableValueString(String varName, boolean initial)
  322.     {
  323.         if (!hasTaskVariable(varName))
  324.             return null;
  325.         return ((String)getTaskVariableValue(varName, initial));
  326.     }
  327.  
  328.     public boolean getTaskVariableValueBool(String varName)
  329.     {
  330.         return getTaskVariableValueBool(varName, false);
  331.     }
  332.  
  333.     public boolean getTaskVariableValueBool(String varName, boolean initial)
  334.     {
  335.         if (!hasTaskVariable(varName))
  336.             return false;
  337.         return ((Boolean)getTaskVariableValue(varName, initial));
  338.     }
  339.  
  340.     /* =========================================== Other methods =============================================== */
  341.  
  342.     /**
  343.      * Get this TaskQueue name (for debug purposes).
  344.      *
  345.      * @return
  346.      */
  347.     public String getTaskQueueName()
  348.     {
  349.         if (_taskQueueName != null)
  350.             return _taskQueueName;
  351.         return "AI_TaskQueue";
  352.     }
  353.  
  354.     /**
  355.      * Change TaskQueue name, used for identyfing while debugging.
  356.      *
  357.      * @param _taskQueueName
  358.      */
  359.     public void setTaskQueueName(String _taskQueueName)
  360.     {
  361.         this._taskQueueName = _taskQueueName;
  362.     }
  363.  
  364.  
  365.     /**
  366.      * Check if specified task instance is queued by AI.
  367.      *
  368.      * @param task
  369.      *
  370.      * @return
  371.      */
  372.     public boolean isTaskQueued(AbstractAITask task)
  373.     {
  374.         return _queuedTasks.contains(task);
  375.     }
  376.  
  377.     /**
  378.      * Check if there is already queued other task instance of the same type (comparing hashCode() method result, not task ids).
  379.      *
  380.      * @param task
  381.      *
  382.      * @return
  383.      */
  384.     public boolean isTaskOfTypeQueued(AbstractAITask task)
  385.     {
  386.         return isTaskQueued(task) || countTaskOfTypeInQueue(task.hashCode()) > 0;
  387.     }
  388.  
  389.     /**
  390.      * Remove specified task (by task id), from AI task queue.
  391.      *
  392.      * @param task
  393.      * @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.
  394.      *
  395.      * @return true    when task was sucessfully removed, false when task not found (not queued).
  396.      */
  397.     public boolean removeTaskFromQueue(AbstractAITask task, boolean releaseId)
  398.     {
  399.         if (!isTaskQueued(task))
  400.         {
  401.             if (releaseId && !task.released())
  402.                 task.free();
  403.             return false;
  404.         }
  405.  
  406. //      boolean locked = _lock.isLocked();
  407. //      if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  408. //          _lock.lock();
  409.         if (!_lock.tryLock())
  410.             return false;
  411.         try
  412.         {
  413.             task.on_remove_from_queue(this);
  414.  
  415.             _queuedTasks.remove(task);
  416.             if (task.random())
  417.                 _rndTaskSelector.remove(task);
  418.  
  419.             if (releaseId && !task.released())
  420.                 task.free();
  421.  
  422.             return true;
  423.         }
  424.         finally
  425.         {
  426. //          if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  427.             _lock.unlock();
  428.         }
  429.     }
  430.  
  431.     /**
  432.      * Process random task "weight" updating procedure.
  433.      *
  434.      * @param task
  435.      *
  436.      * @return true if successfully updated. False when task is not of "random" type, is invalid, not queued, or weight didn't changed.
  437.      */
  438.     protected boolean updateRandomTaskWeight(AbstractAITask task)
  439.     {
  440.         if (!isTaskQueued(task) || !checkTaskUpdate(task))
  441.             return false;
  442.         if (!_lock.tryLock())
  443.             return false;
  444.         try
  445.         {
  446.             int w = task.update_weight();
  447.             if (w > 0 && w != task.weight(false))
  448.             {
  449.                 //          boolean locked = _lock.isLocked();
  450.                 //          if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  451.                 //              _lock.lock();
  452.  
  453.                 //          try
  454.                 //          {
  455.                 _rndTaskSelector.tryUpdateTask(task, w);
  456.                 task.setWeight(w, false);
  457.                 _rndTaskSelector.addIfAbsent(task, true);
  458.  
  459.                 setTaskVariableValue("_lastTaskUpdateId", task.getTaskId());
  460.                 setTaskVariableValue("_lastTaskUpdateHashCode", task.hashCode());
  461.                 setTaskVariableValue("_lastTaskUpdateTimestamp", System.currentTimeMillis());
  462.                 long c = getTaskVariableValueLong("_taskUpdateCounter") + 1;
  463.                 setTaskVariableValue("_taskUpdateCounter", c);
  464.  
  465.                 return true;
  466.                 //          }
  467.                 //          finally
  468.                 //          {
  469.                 //              if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  470.                 //                  _lock.unlock();
  471.                 //          }
  472.             }
  473.         }
  474.         finally
  475.         {
  476.             _lock.unlock();
  477.         }
  478.         return false;
  479.     }
  480.  
  481.     /**
  482.      * Perform manual tasks weights update and rnd task selector reset.
  483.      *
  484.      * @return
  485.      */
  486.     public boolean updateRndSelectorAndTasksWeights()
  487.     {
  488.         return _rndTaskSelector.updateAllTasksAndWeights();
  489.     }
  490.  
  491.     /**
  492.      * Add new task to execution queue.
  493.      *
  494.      * @param task
  495.      * @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)
  496.      *
  497.      * @return true when task was sucessfully added to queue.
  498.      */
  499.     public boolean addTaskToQueue(AbstractAITask task, boolean topOfQueue)
  500.     {
  501.         if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
  502.             return false;
  503.  
  504.         if (!isTaskQueued(task) && canAddTaskToQueue(task))
  505.         {
  506. //          boolean locked = _lock.isLocked();
  507. //          if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  508. //              _lock.lock();
  509.             if (!_lock.tryLock())
  510.                 return false;
  511.             try
  512.             {
  513.                 task.setTaskQueue(this);
  514.  
  515.                 if (task.released())
  516.                     task.getNewId();
  517.  
  518.                 task.setAddedOnTaskRunCycle(getTaskRunCycle());
  519.  
  520.                 if (task.random())
  521.                     _rndTaskSelector.addIfAbsent(task, true);
  522.  
  523.                 if (topOfQueue)
  524.                     _queuedTasks.addFirst(task);
  525.                 else
  526.                     _queuedTasks.add(task);
  527.  
  528.                 task.on_added_to_queue(this);
  529.                 return true;
  530.             }
  531.             finally
  532.             {
  533. //              if (Config.AI_TASK_QUEUE_LOCKING && !locked)
  534.                 _lock.unlock();
  535.             }
  536.         }
  537.         return false;
  538.     }
  539.  
  540.     /**
  541.      * Cancel all tasks, remove from queue, and release all Id's.
  542.      */
  543.     public void clearTaskQueue()
  544.     {
  545.         for (AbstractAITask t : _queuedTasks)
  546.         {
  547.             if (t != null)
  548.                 t.removeFromQueue(true);
  549.         }
  550.     }
  551.  
  552.     /**
  553.      * 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.
  554.      *
  555.      * @return debug info, when removed/updated any task, or empty sting when nothing happened.
  556.      */
  557.     private String processTasks()
  558.     {
  559.         int removed = 0;
  560.         int updated = 0;
  561.  
  562.         ListIterator<AbstractAITask> i = _queuedTasks.listIterator();
  563.         AbstractAITask task;
  564.         while (i.hasNext())
  565.         {
  566.             task = i.next();
  567.             if (task == null)
  568.             {
  569.                 i.remove();
  570.                 continue;
  571.             }
  572.  
  573.             if (checkTaskRemove(task)) // check if it's invalid task, ready for removal
  574.             {
  575.                 task.on_remove_from_queue(this);
  576.                 i.remove(); // remove task.
  577.                 if (task.random()) // if it's "random" task, remove also from random generator
  578.                     _rndTaskSelector.remove(task);
  579.                 if (!task.released()) // release task's id from IdFactory, if not released
  580.                     task.free();
  581.                 removed++;
  582.                 continue;
  583.             }
  584.  
  585.             if (checkTaskUpdate(task) && updateRandomTaskWeight(task)) // check if task is ready to be executed?
  586.                 updated++;
  587.         }
  588.  
  589.         return removed > 0 || updated > 0 ? "procAITasks \n<font color=99ff99>" + getTaskQueueName() + "</font>\nremoved: " + removed + "\nupdated: " + updated : "";
  590.     }
  591.  
  592.     /**
  593.      * Run task.
  594.      *
  595.      * @param task
  596.      *
  597.      * @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,
  598.      * 2 - (for random type tasks only): execution not performed, instead performed task weight update, -3 - not executed task
  599.      */
  600.     public int runTask(AbstractAITask task)
  601.     {
  602.         int res = 0;
  603.         String taskExecDebugMsg = "ai_task_exec \n<font color=99ff99>" + getTaskQueueName() + "</font>\nType: <font color=999999>$taskClassName</font>\nId: $taskId\n$infoMsg";
  604.         int debugtype = 3; // 0 - info, 1 - warning, 2 - error;
  605.         if (task != null)
  606.         {
  607.             String infoMsg = "";
  608.  
  609.             debugtype = 2;
  610.             if (task.runThread())
  611.             {
  612.                 setTaskVariableValue("_lastTaskExecId", task.getTaskId());
  613.                 setTaskVariableValue("_lastTaskExecHashCode", task.hashCode());
  614.                 long c = getTaskVariableValueLong("_taskExecCounter") + 1;
  615.                 setTaskVariableValue("_taskExecCounter", c);
  616.                 setTaskVariableValue("_lastTaskExecTimestamp", System.currentTimeMillis());
  617.                 debugtype = 0;
  618.                 infoMsg += "executed";
  619.                 infoMsg += ", execOk(" + task.execSuccess() + ")";
  620.                 if (!task.execSuccess())
  621.                     debugtype = 1;
  622.                 else
  623.                 {
  624.                     res = 0;
  625.                     if (task.block_think_after_run() && _performThinkTask)
  626.                     {
  627.                         _lastAIThreadRunCycle = getAI().getMainThreadRunCycle();
  628.                         _performThinkTask = false;
  629.                     }
  630.                 }
  631.                 if (task.removeable())
  632.                 {
  633.                     infoMsg += ", removed";
  634.                     res = -1;
  635.                 }
  636.                 else
  637.                 {
  638.                     if (!task.cyclic())
  639.                     {
  640.                         infoMsg += ", resetted";
  641.                         task.reset();
  642.                     }
  643.                     if (!task.random() && !task.cyclic())
  644.                     {
  645.                         infoMsg += ", reAdded";
  646.                         res = 1;
  647.                     }
  648.                     else if (task.random())
  649.                     {
  650.                         infoMsg += ", weightUpdated";
  651.                         res = 2;
  652.                     }
  653.                 }
  654.             }
  655.             else
  656.             {
  657.                 infoMsg += "!executed";
  658.                 res = -3;
  659.             }
  660.  
  661.  
  662.             String dbgType = "";
  663.             switch (debugtype)
  664.             {
  665.                 case 0:
  666.                     dbgType = "_info";
  667.                     break;
  668.                 case 1:
  669.                     dbgType = "_warning";
  670.                     break;
  671.                 case 2:
  672.                     dbgType = "_error";
  673.                     break;
  674.             }
  675.  
  676.             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()))
  677.             {
  678.                 taskExecDebugMsg = taskExecDebugMsg.replace("$taskClassName", task.getTaskTypeName());
  679.                 taskExecDebugMsg = taskExecDebugMsg.replace("$taskId", String.valueOf(task.getTaskId()));
  680.                 taskExecDebugMsg = taskExecDebugMsg.replace("$infoMsg", infoMsg);
  681.  
  682.                 try
  683.                 {
  684.                     switch (debugtype)
  685.                     {
  686.                         case 0:
  687.                             getAI().getAccessor().debug().debugRegisterActorAI_Info(taskExecDebugMsg);
  688.                             break;
  689.                         case 1:
  690.                             getAI().getAccessor().debug().debugRegisterActorAI_Warning(taskExecDebugMsg);
  691.                             break;
  692.                         case 2:
  693.                             getAI().getAccessor().debug().debugRegisterActorAI_Error(taskExecDebugMsg);
  694.                             break;
  695.                     }
  696.  
  697.                     String trace = getAI().getAccessor().debug().executionTrace();
  698.                     if (trace != null)
  699.                         getAI().getAccessor().debug().getEventsAndIntentionsHistory().putIfAbsent(System.currentTimeMillis(), "<br1>- " + trace);
  700.                 }
  701.                 catch (Exception e)
  702.                 {
  703.                 }
  704.             }
  705.         }
  706.         else
  707.             res = -2;
  708.  
  709.         return res;
  710.     }
  711.  
  712.     protected boolean execTasksFromQueue(boolean onlyCyclic)
  713.     {
  714.         if (_executingQueueTask || _queuedTasks.isEmpty())
  715.             return false;
  716.         _executingQueueTask = true;
  717.  
  718.         int removed = 0;
  719.         int executed = 0;
  720.         int updated = 0;
  721.         boolean abort = false;
  722.         try
  723.         {
  724.             for (AbstractAITask task : _queuedTasks)
  725.             {
  726.                 if (abort)
  727.                     break;
  728.  
  729.                 if (task != null && !task.random() && task.cyclic() == onlyCyclic && validateTask(task))
  730.                 {
  731.                     int result = runTask(task);
  732.                     switch (result)
  733.                     {
  734.                         case -3:
  735.                             // Not executed
  736.                             break;
  737.                         case -2:
  738.                             // NPE
  739.                             break;
  740.                         case -1:
  741. //                          if (checkTaskRemove(task) && task.removeFromQueue(true))
  742. //                              removed++;
  743.                             executed++;
  744.                             abort = !onlyCyclic;
  745.                             break;
  746.                         case 0:
  747.                             // OK
  748.                             executed++;
  749.                             abort = !onlyCyclic;
  750.                             break;
  751.                         case 1: // only for not cyclic and not random tasks.
  752. //                          _lock.lock();
  753. //                          try
  754.                         {
  755.                             _queuedTasks.remove(task); // remove task.
  756.                             _queuedTasks.addFirst(task); // readd at queue top
  757.                         }
  758. //                          finally
  759. //                          {
  760. //                              _lock.unlock();
  761. //                          }
  762.                         executed++;
  763.                         abort = !onlyCyclic;
  764.                         break;
  765.                         case 2: // cyclic / random task updated weight after exec.
  766. //                          if (checkTaskUpdate(task) && updateRandomTaskWeight(task))
  767. //                              updated++;
  768.                             executed++;
  769.                             abort = !onlyCyclic;
  770.                             break;
  771.                     }
  772.                 }
  773.             }
  774.         }
  775.         catch (Exception e)
  776.         {
  777.             _log.log(Level.WARNING, "AI " + (onlyCyclic ? "Cyclic" : "") + "TaskExecution exception: " + e.getMessage(), e);
  778.         }
  779.         finally
  780.         {
  781.             _executingQueueTask = false;
  782.         }
  783.         return executed > 0;
  784.     }
  785.  
  786.     public int getRandomTasksQueueSize()
  787.     {
  788.         return _rndTaskSelector.size();
  789.     }
  790.  
  791.     protected boolean execNextRandomTaskFromQueue()
  792.     {
  793.         if (_executingQueueTask || _queuedTasks.isEmpty())
  794.             return false;
  795.         _executingQueueTask = true;
  796.  
  797.         try
  798.         {
  799.             _rndTaskSelector.reset();
  800.             int maxRndCycles = getRandomTasksQueueSize();
  801.             while (_rndTaskSelector.hasNext() && maxRndCycles > 0)
  802.             {
  803.                 AbstractAITask rndTask = _rndTaskSelector.next(true);
  804.                 maxRndCycles--;
  805.  
  806.                 if (!validateTask(rndTask))
  807.                     continue;
  808.  
  809.                 int result = runTask(rndTask);
  810.                 switch (result)
  811.                 {
  812.                     case -3:
  813.                         // Not executed
  814.                         break;
  815.                     case -2:
  816.                         // NPE
  817.                         break;
  818.                     case -1:
  819. //                      if (checkTaskRemove(rndTask))
  820. //                          rndTask.removeFromQueue(true); // remove task.
  821.                         return true;
  822.                     case 0:
  823.                         // OK
  824.                         return true;
  825.                     case 2: // cyclic / random task updated weight after exec.
  826.                         return true;//checkTaskUpdate(rndTask) && updateRandomTaskWeight(rndTask);
  827.                 }
  828.             }
  829.         }
  830.         catch (Exception e)
  831.         {
  832.             _log.log(Level.WARNING, "AI RandomTaskExecution exception: " + e.getMessage(), e);
  833.         }
  834.         finally
  835.         {
  836.             _executingQueueTask = false;
  837.         }
  838.         return false;
  839.     }
  840.  
  841.     /**
  842.      * Returns AI TaskQueue debug info (list of tasks and statuses).
  843.      *
  844.      * @return
  845.      */
  846.     public String getTaskQueueInfo()
  847.     {
  848.         if (_queuedTasks.isEmpty())
  849.             return ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nTask Queue [" + getTaskQueueName() + "] is empty.\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
  850.  
  851.         String r = ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nAI Task Queue [" + getTaskQueueName() + "]\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
  852.         int tNum = 1;
  853.         for (AbstractAITask t : _queuedTasks)
  854.         {
  855.             r += "\n" + tNum + ") " + t.getTaskTypeName() + " " + t.toString(true).replace(" ", "\n   - ") + (tNum < _queuedTasks.size() ? "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_C) : "");
  856.             tNum++;
  857.         }
  858.         r += "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
  859.         return r;
  860.     }
  861.  
  862.     public String getVariablesInfo()
  863.     {
  864.         String r = ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A) + "\nTask Queue Variables\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
  865.         int num = 1;
  866.         for (AITaskSimpleVar v : _tasksVariables.values())
  867.         {
  868.             r += "\n" + (num > 1 ? ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_C) + "\n" : "") + num + ") " + v;
  869.             num++;
  870.         }
  871.         r += "\n" + ExtUtil.getChatPredefines(ExtUtil.SL2ChatPredefine.LINE_SEPARATOR_A);
  872.         return r;
  873.     }
  874.  
  875.     /**
  876.      * Returns number of tasks of certain class name, currently queued.
  877.      *
  878.      * @param taskClassName
  879.      *
  880.      * @return
  881.      */
  882.     public int countTaskOfTypeInQueue(String taskClassName)
  883.     {
  884.         if (taskClassName == null || taskClassName.isEmpty())
  885.             return 0;
  886.         return countTaskOfTypeInQueue(taskClassName.hashCode());
  887.     }
  888.  
  889.     /**
  890.      * Returns number of tasks of certain class name, currently queued.
  891.      *
  892.      * @param hashCode
  893.      *
  894.      * @return
  895.      */
  896.     public int countTaskOfTypeInQueue(int hashCode)
  897.     {
  898.         if (_queuedTasks.isEmpty())
  899.             return 0;
  900.  
  901.         int c = 0;
  902.         for (AbstractAITask t : _queuedTasks)
  903.         {
  904.             if (t != null && !checkTaskRemove(t) && t.hashCode() == hashCode)
  905.                 c++;
  906.         }
  907.         return c;
  908.     }
  909.  
  910.     /**
  911.      * 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
  912.      * method to get certain types of tasks when needed.
  913.      *
  914.      * @param taskIdOrHashCode
  915.      *
  916.      * @return
  917.      */
  918.     public FastList<AbstractAITask> getQueuedTasks(int taskIdOrHashCode)
  919.     {
  920.         FastList<AbstractAITask> tasks = new FastList<AbstractAITask>();
  921.         if (_queuedTasks.isEmpty())
  922.             return tasks;
  923.  
  924.         for (AbstractAITask t : _queuedTasks)
  925.         {
  926.             if (t != null && !t.removeable() && ((!t.released() && t.getTaskId() == taskIdOrHashCode) || t.hashCode() == taskIdOrHashCode))
  927.                 tasks.add(t);
  928.         }
  929.         return tasks;
  930.     }
  931.  
  932.     /**
  933.      * @param hashCode
  934.      *
  935.      * @return true if at least one task with that hashCode currently in tasks queue.
  936.      */
  937.     public boolean hasTaskOfTypeInQueue(int hashCode)
  938.     {
  939.         return countTaskOfTypeInQueue(hashCode) > 0;
  940.     }
  941.  
  942.     /**
  943.      * @param taskClassName
  944.      *
  945.      * @return true if at least one task with taskClassName currently in tasks queue.
  946.      */
  947.     public boolean hasTaskOfTypeInQueue(String taskClassName)
  948.     {
  949.         return countTaskOfTypeInQueue(taskClassName) > 0;
  950.     }
  951.  
  952.     /**
  953.      * Validates task's conditions, if it can be queued.
  954.      *
  955.      * @param task
  956.      *
  957.      * @return
  958.      */
  959.     public boolean canAddTaskToQueue(AbstractAITask task)
  960.     {
  961.         if (!task.valid())
  962.             return false;
  963.         if (task.max_task_instances() < 0)
  964.             return true;
  965.         if (task.max_task_instances() == 0)
  966.             return false;
  967.         return countTaskOfTypeInQueue(task.hashCode()) < task.max_task_instances();
  968.     }
  969.  
  970.  
  971.     /**
  972.      * Executed from within a task, to register global execution count of certain task type.
  973.      *
  974.      * @param task
  975.      */
  976.     public void registerTaskTypeExecCountAndTimestamp(AbstractAITask task)
  977.     {
  978.         registerTaskTypeExecCountAndTimestamp(task.hashCode());
  979.     }
  980.  
  981.     /**
  982.      * Executed from within a task, to register global execution count of certain task type.
  983.      *
  984.      * @param taskTypeHashCode
  985.      */
  986.     public void registerTaskTypeExecCountAndTimestamp(int taskTypeHashCode)
  987.     {
  988. //       Object tte = getTaskVariableValue("_tte_counters_"+taskTypeHashCode);
  989.         Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
  990.         if (t == null || t.length < 2)
  991.         {
  992.             t = new Long[2];
  993.             t[1] = 0L;
  994.         }
  995.         t[0] = System.currentTimeMillis();
  996.         t[1]++;
  997.         _taskByTypeExecCountAndTimestamps.put(taskTypeHashCode, t);
  998.     }
  999.  
  1000.     public int getTaskTypeExecCount(AbstractAITask task)
  1001.     {
  1002.         return getTaskTypeExecCount(task.hashCode());
  1003.     }
  1004.  
  1005.     public int getTaskTypeExecCount(int taskTypeHashCode)
  1006.     {
  1007.         Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
  1008.         if (t == null || t.length < 2)
  1009.             return 0;
  1010.  
  1011.         return t[1].intValue();
  1012.     }
  1013.  
  1014.     public long getTaskTypeLastExecTimestamp(AbstractAITask task)
  1015.     {
  1016.         return getTaskTypeLastExecTimestamp(task.hashCode());
  1017.     }
  1018.  
  1019.     public long getTaskTypeLastExecTimestamp(int taskTypeHashCode)
  1020.     {
  1021.         Long[] t = _taskByTypeExecCountAndTimestamps.get(taskTypeHashCode);
  1022.         if (t == null || t.length < 2)
  1023.             return 0;
  1024.  
  1025.         return t[0];
  1026.     }
  1027.  
  1028.     /**
  1029.      * Access list of queued tasks.
  1030.      *
  1031.      * @return
  1032.      */
  1033.     public Collection<AbstractAITask> getQueuedTasks()
  1034.     {
  1035.         return _queuedTasks;
  1036.     }
  1037.  
  1038.     /**
  1039.      * Detemine if any task locked think task execution for one AI thread cycle. See {@link #resetThinkTaskBlock()}.
  1040.      *
  1041.      * @return
  1042.      */
  1043.     public boolean isPerformThinkTask()
  1044.     {
  1045.         return _performThinkTask;
  1046.     }
  1047.  
  1048.     /**
  1049.      * Lifts EVT_THINK blockade for AI process, put by one of tasks, that request to skipp "think" cycle after execution.
  1050.      */
  1051.     public void resetThinkTaskBlock()
  1052.     {
  1053.         _performThinkTask = true;
  1054.     }
  1055.  
  1056.  
  1057.     private int _taskRunCounter = 0, _taskRunCycle = 0;
  1058.     private long _validateQueueRunTs = 0;
  1059.     private int _lastAIThreadRunCycle = 0;
  1060.  
  1061.     /**
  1062.      * 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
  1063.      * 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
  1064.      * determine, if queue is running, see {@link #isTaskQueueRunning()}
  1065.      *
  1066.      * @return
  1067.      */
  1068.     public int getTaskRunCycle()
  1069.     {
  1070.         return isTaskQueueRunning() ? _taskRunCycle : -1;
  1071.     }
  1072.  
  1073.     private int execNextRandomTaskCounter = 0;
  1074.     private boolean runCleanup = false;
  1075.  
  1076.     @Override
  1077.     public void run()
  1078.     {
  1079.         if (GameServer.serverStartingUp || _taskQueueThread == null || (hasAI() && getAI().isThrowedAndFlying()))
  1080.             return;
  1081.  
  1082.         if (!hasAI())
  1083.         {
  1084.             stopTaskQueue();
  1085.             return;
  1086.         }
  1087.  
  1088. //      boolean unlock = false;
  1089. //      if (Config.AI_TASK_QUEUE_LOCKING)
  1090. //      {
  1091. //          unlock = _lock.tryLock();
  1092. //          if (!unlock)
  1093. //              return;
  1094. //      }
  1095.         try
  1096.         {
  1097.  
  1098.             _taskRunCounter++;
  1099.  
  1100.             if (_taskRunCounter % 3 == 0 || _taskRunCounter % 4 == 0)
  1101.             {
  1102.                 _taskRunCycle++;
  1103.                 if (getAI().getMainThreadRunCycle() < 0 || _lastAIThreadRunCycle < getAI().getMainThreadRunCycle())
  1104.                     _performThinkTask = true;
  1105.  
  1106.                 if (_taskRunCounter % 4 == 0)
  1107.                 {
  1108.                     // try exec random task
  1109.                     if (!execTasksFromQueue(false))
  1110.                     {
  1111.                         // when failed do not always try executing other random task, as the 2nd method performs task randomizer reset!
  1112.                         execNextRandomTaskCounter++;
  1113.                         if (execNextRandomTaskCounter > 1)
  1114.                         {
  1115.                             execNextRandomTaskCounter = 0;
  1116.                             execNextRandomTaskFromQueue();
  1117.                         }
  1118.                     }
  1119.                 }
  1120.                 else // exec cyclic tasks
  1121.                     execTasksFromQueue(true);
  1122.             }
  1123.             else if (_validateQueueRunTs <= 0 || System.currentTimeMillis() - _validateQueueRunTs > 1000)
  1124.             {
  1125.                 _validateQueueRunTs = System.currentTimeMillis();
  1126.                 if (runCleanup)
  1127.                 {
  1128.                     /* ================= PROCESS TASKS (VALIDATE AND CLEAN QUEUE), PERFORM UPDATES, EXECUTE GENERAL TASKS, FROM TOP OF THE QUEUE, TO BOTTOM ================ */
  1129.                     String prcDebug = processTasks();
  1130.                     if (!prcDebug.isEmpty() && getActor().isAIDebug() && Config.AI_log_this(getActor(), "proc_ai_tasks"))
  1131.                     {
  1132.                         try {getAI().getAccessor().debug().debugRegisterActorAI_Info(prcDebug); }
  1133.                         catch (Exception e) { }
  1134.                     }
  1135.                     /* ================= CHOOSE 1 RANDOM TASK FROM RANDOM TASKS, BY IT'S CURRENT WEIGHT LEVEL, AND TRY TO EXECUTE / PERFORM UPDATE ================ */
  1136.                 }
  1137.                 else
  1138.                     validateQueueTasks();
  1139.  
  1140.                 runCleanup = !runCleanup;
  1141.             }
  1142.         }
  1143.         catch (Exception e)
  1144.         {
  1145.             _log.log(Level.WARNING, this + ": Exception " + e.getMessage(), e);
  1146.         }
  1147. //      finally
  1148. //      {
  1149. //          if (unlock)
  1150. //              _lock.unlock();
  1151. //      }
  1152.     }
  1153.  
  1154.     /**
  1155.      * Used to manually execute and process tasks on queue. If tast queue is running, this method will abort and always return false.
  1156.      *
  1157.      * @return
  1158.      */
  1159.     public boolean execTasksQueue()
  1160.     {
  1161.         if (isTaskQueueRunning())
  1162.             return false;
  1163.  
  1164.         /* ================= PROCESS TASKS (VALIDATE AND CLEAN QUEUE), PERFORM UPDATES, EXECUTE GENERAL TASKS, FROM TOP OF THE QUEUE, TO BOTTOM ================ */
  1165.         String prcDebug = processTasks();
  1166.         if (!prcDebug.isEmpty() && getActor().isAIDebug() && Config.AI_log_this(getActor(), "proc_ai_tasks"))
  1167.         {
  1168.             try { getAI().getAccessor().debug().debugRegisterActorAI_Info(prcDebug); } catch (Exception e) { }
  1169.         }
  1170.         /* ================= CHOOSE 1 RANDOM TASK FROM RANDOM TASKS, BY IT'S CURRENT WEIGHT LEVEL, AND TRY TO EXECUTE / PERFORM UPDATE ================ */
  1171.         _performThinkTask = true;
  1172.         boolean executed = false;
  1173.         executed |= execTasksFromQueue(false);
  1174.         if (!executed)
  1175.             executed |= execNextRandomTaskFromQueue();
  1176.         executed |= execTasksFromQueue(true);
  1177.         return executed;
  1178.     }
  1179.  
  1180.     /**
  1181.      * Tries to execute task (from current queue), by specified class name.
  1182.      *
  1183.      * @param taskClassName name of task class to execute
  1184.      *
  1185.      * @return true on success, false when execution is not allowed, or task of that class is not on current task queue.
  1186.      */
  1187.     public boolean runTaskOfType(String taskClassName)
  1188.     {
  1189.         return runTaskOfType(taskClassName.hashCode());
  1190.     }
  1191.  
  1192.     /**
  1193.      * Tries to execute task (from current queue), by specified hashCode.
  1194.      *
  1195.      * @param hashCodeOrTaskId hashCode of task to execute
  1196.      *
  1197.      * @return true on success, false when execution is not allowed, or task of that hash code not in queue.
  1198.      */
  1199.     public boolean runTaskOfType(int hashCodeOrTaskId)
  1200.     {
  1201.         FastList<AbstractAITask> tasks = getQueuedTasks(hashCodeOrTaskId);
  1202.         if (tasks.isEmpty())
  1203.             return false;
  1204.  
  1205.         AbstractAITask task = null;
  1206.         if (tasks.size() == 1)
  1207.             task = tasks.getFirst();
  1208.         else
  1209.         {
  1210.             RndTaskSelector selector = new RndTaskSelector(tasks);
  1211.             while (selector.hasNext())
  1212.             {
  1213.                 task = selector.next(true);
  1214.                 if (task.valid())
  1215.                     break;
  1216.                 else
  1217.                     task = null;
  1218.             }
  1219.         }
  1220.         if (task != null && validateTask(task))
  1221.         {
  1222.             int result = runTask(task);
  1223.             switch (result)
  1224.             {
  1225.                 case -3:
  1226.                     // Not executed
  1227.                     return false;
  1228.                 case -2:
  1229.                     // NPE
  1230.                     return false;
  1231.                 case -1:
  1232.                     return true;
  1233.                 case 0:
  1234.                     // OK
  1235.                     return true;
  1236.                 case 2: // cyclic / random task updated weight after exec.
  1237.                     return true;//checkTaskUpdate(rndTask) && updateRandomTaskWeight(rndTask);
  1238.             }
  1239.         }
  1240.         return false;
  1241.     }
  1242.  
  1243.     public ITaskQueueController getController()
  1244.     {
  1245.         return _controller;
  1246.     }
  1247.  
  1248.     public void setController(final ITaskQueueController controller)
  1249.     {
  1250.         _controller = controller;
  1251.     }
  1252. }
  1253.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement