Task.pm
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:11k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Task framework
  3. #  Copyright (c) 2006 OpenKore Team
  4. #
  5. #  This software is open source, licensed under the GNU General Public
  6. #  License, version 2.
  7. #  Basically, this means that you're allowed to modify and distribute
  8. #  this software. However, if you distribute modified versions, you MUST
  9. #  also distribute the source code.
  10. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  11. #########################################################################
  12. ##
  13. # MODULE DESCRIPTION: Abstract task base class.
  14. #
  15. # This is the abstract base class for all tasks. Please read
  16. # <a href="http://www.openkore.com/wiki/index.php/AI_subsystem_and_task_framework_overview">
  17. # the AI subsystem and task framework overview
  18. # </a>
  19. # for an overview.
  20. #
  21. # <h3>Notes on priority constants</h3>
  22. # The only things you may assume about the values of priority contants are:
  23. # `l
  24. # - Each priority constant differ at least a value of 100 from other priority constants.
  25. #   That is, <tt>abs(c1 - c2) >= 300</tt> if c1 and c2 are two random priority constants.
  26. # - A higher value means a higher priority.
  27. # `l`
  28. package Task;
  29. use strict;
  30. use Carp;
  31. use Carp::Assert;
  32. use Modules 'register';
  33. use Utils::CallbackList;
  34. use Utils::Set;
  35. ####################################
  36. ### CATEGORY: Priority constants
  37. ###################################
  38. ##
  39. # Task::LOW_PRIORITY
  40. #
  41. # Indicates a low task priority.
  42. use constant LOW_PRIORITY    => 100;
  43. ##
  44. # Task::NORMAL_PRIORITY
  45. #
  46. # Indicates a normal task priority.
  47. use constant NORMAL_PRIORITY => 500;
  48. ##
  49. # Task::HIGH_PRIORITY
  50. #
  51. # Indicates a high task priority.
  52. use constant HIGH_PRIORITY   => 1000;
  53. ##
  54. # Task::USER_PRIORITY
  55. #
  56. # Priority used for user-invoked commands.
  57. use constant USER_PRIORITY   => 5000;
  58. ###################################
  59. ### CATEGORY: Status constants
  60. ###################################
  61. ##
  62. # Task::INACTIVE
  63. #
  64. # Indicates that the task has just been created.
  65. use constant INACTIVE    => 0;
  66. ##
  67. # Task::RUNNING
  68. #
  69. # Indicates that the task is running.
  70. use constant RUNNING     => 1;
  71. ##
  72. # Task::INTERRUPTED
  73. #
  74. # Indicates that the task is interrupted, and not running.
  75. use constant INTERRUPTED => 2;
  76. ##
  77. # Task::STOPPED
  78. #
  79. # Indicates that the task is stopped. A stopped task cannot resume.
  80. use constant STOPPED     => 3;
  81. ##
  82. # Task::DONE
  83. #
  84. # Indicates that the task is completed. A completed task cannot be stopped or interrupted.
  85. use constant DONE        => 4;
  86. ####################################
  87. ### CATEGORY: Constructor
  88. ###################################
  89. ##
  90. # Task->new(options...)
  91. # Ensures: result->getStatus() == Task::INACTIVE
  92. #
  93. # Create a new Task object. The following options are allowed:
  94. # `l
  95. # - <tt>name</tt> - A name for this task. $Task->getName() will return this name.
  96. #                   If not specified, the class's name (excluding the "Task::" prefix) will be used as name.
  97. # - <tt>priority</tt> - A priority for this task. $Task->getPriority() will return this value.
  98. #                       The default priority is Task::NORMAL_PRIORITY
  99. # - <tt>mutexes</tt> - A reference to an array of mutexes. $Task->getMutexes() will return this value.
  100. #                      The default is an empty mutex list.
  101. # `l`
  102. sub new {
  103. my $class = shift;
  104. my %args = @_;
  105. my $allowed = new Set("name", "priority", "mutexes");
  106. my %self;
  107. foreach my $key (keys %args) {
  108. if ($allowed->has($key)) {
  109. $self{"T_$key"} = $args{$key};
  110. }
  111. }
  112. if (!defined $self{T_name}) {
  113. $self{T_name} = $class;
  114. $self{T_name} =~ s/.*:://;
  115. }
  116. $self{T_status} = INACTIVE;
  117. $self{T_priority} = NORMAL_PRIORITY if (!defined $self{T_priority});
  118. $self{T_mutexes} = [] if (!defined $self{T_mutexes});
  119. $self{T_onMutexesChanged} = new CallbackList("onMutexesChanged");
  120. $self{T_onStop} = new CallbackList("onStop");
  121. return bless %self, $class;
  122. }
  123. sub _getStatusName {
  124. my ($status) = @_;
  125. if ($status == INACTIVE) {
  126. return 'INACTIVE';
  127. } elsif ($status == RUNNING) {
  128. return 'RUNNING';
  129. } elsif ($status == INTERRUPTED) {
  130. return 'INTERRUPTED';
  131. } elsif ($status == STOPPED) {
  132. return 'STOPPED';
  133. } elsif ($status == DONE) {
  134. return 'DONE';
  135. } else {
  136. return $status;
  137. }
  138. }
  139. sub _assertStatus {
  140. my $self = shift;
  141. my $currentStatus = $self->{T_status};
  142. foreach my $status (@_) {
  143. if ($status == $currentStatus) {
  144. return;
  145. }
  146. }
  147. my @expectedStatuses = map { _getStatusName($_) } @_;
  148. Carp::confess("The current task's status should be one of: (" . join(',', @expectedStatuses) . ")n" .
  149. "But it's actually: " . _getStatusName($currentStatus) . "n");
  150. }
  151. ############################
  152. ### CATEGORY: Queries
  153. ############################
  154. ##
  155. # String $Task->getName()
  156. # Ensures: $result ne ""
  157. #
  158. # Returns a human-readable name for this task.
  159. sub getName {
  160. return $_[0]->{T_name};
  161. }
  162. ##
  163. # $Task->getStatus()
  164. #
  165. # Returns the task's status. This is one of Task::RUNNING, Task::INTERRUPTED, Task::STOPPED or Task::DONE.
  166. sub getStatus {
  167. return $_[0]->{T_status};
  168. }
  169. ##
  170. # Hash* $Task->getError()
  171. # Requires: $self->getStatus() == Task::DONE
  172. #
  173. # If the status is Task::DONE, then return information about the error (if the task
  174. # completed with an error).
  175. # Otherwise (if the task completed successfully), return undef.
  176. #
  177. # The error information is a reference to a hash, containing two items:
  178. # `l
  179. # - code - The error code.
  180. # - message - The error message.
  181. # `l`
  182. sub getError {
  183. $_[0]->_assertStatus(DONE) if DEBUG;
  184. return $_[0]->{T_error};
  185. }
  186. ##
  187. # Array<String>* $Task->getMutexes()
  188. # Ensures: defined(result)
  189. #
  190. # Returns a reference to an array of mutexes for this task. Note that the mutex list may
  191. # change during a Task's life time. This list must not be modified outside the Task object.
  192. #
  193. # If you override this method, then you <b>must</b> ensure that when the mutex list changes,
  194. # you trigger a onMutexesChanged event. Otherwise the task manager will not behave correctly.
  195. sub getMutexes {
  196. return $_[0]->{T_mutexes};
  197. }
  198. ##
  199. # int $Task->getPriority()
  200. #
  201. # Get the priority for this task. This priority is guaranteed to never change during a Task's
  202. # life time.
  203. sub getPriority {
  204. return $_[0]->{T_priority};
  205. }
  206. #####################################
  207. ### CATEGORY: Events
  208. #####################################
  209. ##
  210. # CallbackList $Task->onMutexesChanged()
  211. #
  212. # This event is triggered when the mutex list for this task has changed.
  213. sub onMutexesChanged {
  214. return $_[0]->{T_onMutexesChanged};
  215. }
  216. ##
  217. # CallbackList $Task->onStop()
  218. #
  219. # This event is triggered when the task's status has been set to Task::STOPPED.
  220. sub onStop {
  221. return $_[0]->{T_onStop};
  222. }
  223. #####################################
  224. ### CATEGORY: Protected commands
  225. #####################################
  226. ##
  227. # void $Task->setError(code, message)
  228. # code: An error code.
  229. # message: An error message.
  230. # Requires: $self->getStatus() == Task::INACTIVE or Task::RUNNING
  231. #
  232. # Indicate that the task has been completed, but with an error.
  233. # The status will be set to Task::DONE, and $Task->getError() will return
  234. # the error information passed to this method.
  235. #
  236. # Do not call this method outside $Task->iterate(), or bad things will happen!
  237. sub setError {
  238. my ($self, $code, $message) = @_;
  239. $self->_assertStatus(INACTIVE, RUNNING) if DEBUG;
  240. $self->{T_error} = {
  241. code => $code,
  242. message => $message
  243. };
  244. $self->{T_status} = DONE;
  245. }
  246. ##
  247. # void $Task->setDone()
  248. # Requires: $self->getStatus() == Task::INACTIVE or Task::RUNNING
  249. #
  250. # Indicate that the task has been completed, without error. The
  251. # status will be set to Task::DONE.
  252. #
  253. # Do not call this method outside $Task->iterate(), or bad things will happen!
  254. sub setDone {
  255. my ($self) = @_;
  256. $self->_assertStatus(INACTIVE, RUNNING) if DEBUG;
  257. $self->{T_status} = DONE;
  258. }
  259. ##
  260. # void $Task->setStopped()
  261. # Requires: $self->getStatus() == Task::RUNNING, Task::INACTIVE or Task::INTERRUPTED
  262. # Ensures: $self->getStatus() == Task::STOPPED
  263. #
  264. # Set the task's status to Task::STOPPED and trigger an onStop event.
  265. # This is useful for tasks that cannot stop immediately
  266. # when stop() is called: they can mark the task as stopped when appropriate.
  267. sub setStopped {
  268. my ($self) = @_;
  269. $self->_assertStatus(INACTIVE, RUNNING, INTERRUPTED) if DEBUG;
  270. $self->{T_status} = STOPPED;
  271. $self->{T_onStop}->call($self);
  272. }
  273. ##
  274. # void $Task->setMutexes(mutexes...)
  275. #
  276. # Set the currently active mutexes for this task. This will trigger an
  277. # onMutexesChanged event.
  278. #
  279. # You should only call this method inside the class's iterate() method,
  280. # or during initialization. Otherwise you may confuse the task manager.
  281. sub setMutexes {
  282. my $self = shift;
  283. $self->{T_mutexes} = @_;
  284. $self->{T_onMutexesChanged}->call($self);
  285. }
  286. #####################################
  287. ### CATEGORY: Public commands
  288. #####################################
  289. ##
  290. # void $Task->activate()
  291. # Requires: $self->getStatus() == Task::INACTIVE
  292. # Ensures: $self->getStatus() == Task::RUNNING
  293. #
  294. # Notify a task that it will be activated. Activation happens only once:
  295. # just before iterate() is called, but only if the task has just been created.
  296. # This allows the task to perform initialization.
  297. #
  298. # This method will be called by the task manager.
  299. sub activate {
  300. $_[0]->_assertStatus(INACTIVE) if DEBUG;
  301. $_[0]->{T_status} = RUNNING;
  302. }
  303. ##
  304. # void $Task->interrupt()
  305. # Requires: $self->getStatus() == Task::RUNNING
  306. # Ensures: $self->getStatus() == Task::INTERRUPTED
  307. #
  308. # Notify a (running) task that it is about to be interrupted. The task may take necessary actions
  309. # (like updating internal timers) in preparation for interruption. The task must immediately
  310. # cease all actions, and set the status to Task::INTERRUPTED.
  311. #
  312. # This method should only be called by the task manager.
  313. #
  314. # Task implementors may override this method to implement code for interruption handling.
  315. sub interrupt {
  316. $_[0]->_assertStatus(RUNNING) if DEBUG;
  317. $_[0]->{T_status} = INTERRUPTED;
  318. }
  319. ##
  320. # void $Task->resume()
  321. # Requires: $self->getStatus() == Task::INTERRUPTED
  322. # Ensures: $self->getStatus() == Task::RUNNING
  323. #
  324. # Notify an (interrupted) task that it is about to be resumed. The task may take
  325. # necessary actions in prepration for resuming. The task must set its status to
  326. # Task::RUNNING.
  327. #
  328. # This method should only be called by the task manager.
  329. #
  330. # Task implementors may override this method to implement code for resume handling.
  331. sub resume {
  332. $_[0]->_assertStatus(INTERRUPTED) if DEBUG;
  333. $_[0]->{T_status} = RUNNING;
  334. }
  335. ##
  336. # void $Task->stop()
  337. # Requires: $self->getStatus() == Task::RUNNING, Task::INACTIVE or Task::INTERRUPTED
  338. #
  339. # Notify a task that it must completely stop. When the task is actually stopped,
  340. # the status must be set to Task::STOPPED.
  341. #
  342. # The default behavior is to immediate set the status to Task::STOPPED
  343. # by calling $Task->setStopped(), thereby triggering an onStop event.
  344. # Task implementors may override this method to implement custom stop handling.
  345. # You may choose to stop the task after a period of time, instead of immediately.
  346. #
  347. # This method may be called by anybody, not just the task manager.
  348. sub stop {
  349. $_[0]->setStopped();
  350. }
  351. ##
  352. # void $Task->iterate()
  353. # Requires: $self->getStatus() == Task::RUNNING
  354. #
  355. # Run one iteration of this task. Task implementors must override this method to
  356. # implement task code.
  357. sub iterate {
  358. $_[0]->_assertStatus(RUNNING) if DEBUG;
  359. }
  360. 1;