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

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Object list
  3. #
  4. #  Copyright (c) 2006 OpenKore Development Team
  5. #
  6. #  This software is open source, licensed under the GNU General Public
  7. #  License, version 2.
  8. #  Basically, this means that you're allowed to modify and distribute
  9. #  this software. However, if you distribute modified versions, you MUST
  10. #  also distribute the source code.
  11. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  12. #########################################################################
  13. ##
  14. # MODULE DESCRIPTION: List class with constant item indices and event support
  15. #
  16. # The ObjectList class is an array list, and differentiates from the standard
  17. # Perl array in the following ways:
  18. # <ol>
  19. # <li> It will only contain Objects. That is, only blessed scalars. </li>
  20. # <li> It guarantees that, when you add an item to the list, its index will
  21. #      always remain constant until that item is removed from the list. </li>
  22. # <li> It can emit an event when items are added or removed, or
  23. #      when the list is cleared. </li>
  24. # <li> When you iterate through the list, it is guaranteed that you will never
  25. #      encounter undefined items. </li>
  26. # </ol>
  27. #
  28. # ObjectList is used to implement the actors list, the inventory list, etc.
  29. # Especially property (2) is important: for instance, it is desirable that
  30. # monster in the monster list will always have the same list index, so that
  31. # when someone types 'ml' and 'a 2', Kore will attack monster 2 as he saw
  32. # earlier in the list, and not some other monster (as a result of an index
  33. # change).
  34. #
  35. # Note that subclasses of ObjectList may require stronger preconditions.
  36. #
  37. # Subclasses: @CLASS(ActorList)
  38. #
  39. # <h3>Item indices and iteration</h3>
  40. # The index, as returned by the $ObjectList->add(), must not be treated as an
  41. # index in a regular Perl array. Which means that you can't assume that that
  42. # index is always smaller than $ObjectList->size(). So the index that
  43. # $ObjectList->add() returns should only be used for:
  44. # `l
  45. # - Uniquely identifying an item in the list.
  46. # - Retrieving an item from the list using $ObjectList->get().
  47. # `l`
  48. #
  49. # To iterate through the list, you must <b>not</b> write this:
  50. # <pre class="example">
  51. # for (my $i = 0; $i < $list->size(); $i++) {
  52. #     doSomethingWith($list->get($i));
  53. # }
  54. # </pre>
  55. # Use $ObjectList->getItems() instead:
  56. # <pre class="example">
  57. # my $items = $list->getItems();
  58. # foreach my $item (@{$items}) {
  59. #     doSomethingWith($item);
  60. # }
  61. # </pre>
  62. package ObjectList;
  63. use strict;
  64. use Carp::Assert;
  65. use Scalar::Util;
  66. use Utils::CallbackList;
  67. ### CATEGORY: Class ObjectList
  68. ##
  69. # ObjectList ObjectList->new()
  70. # Ensures:
  71. #     $self->size() == 0
  72. #     $self->onAdd()->size() == 0
  73. #     $self->onRemove()->size() == 0
  74. #     $self->onClearBegin()->size() == 0
  75. #     $self->onClearEnd()->size() == 0
  76. #
  77. # Construct a new ObjectList.
  78. sub new {
  79. my ($class) = @_;
  80. my %self = (
  81. # Array<Object> items
  82. # The items in this list. May contain empty elements.
  83. #
  84. # Invariant: defined(items)
  85. OL_items => [],
  86. # Array<Object> cItems
  87. # Same as $items, but doesn't contain any empty elements.
  88. # An index in $items may not refer to the same item in
  89. # this array.
  90. #
  91. # Invariant:
  92. #     defined(cItems)
  93. #     cItems.size <= items.size
  94. #     for all $i in [0 .. cItems.size - 1]:
  95. #         exists $cItems[$i]
  96. OL_cItems => [],
  97. # Invariant: defined(onAdd)
  98. OL_onAdd => new CallbackList(),
  99. # Invariant: defined(onRemove)
  100. OL_onRemove => new CallbackList(),
  101. # Invariant: defined(onClearBegin)
  102. OL_onClearBegin => new CallbackList(),
  103. # Invariant: defined(onClearEnd)
  104. OL_onClearEnd => new CallbackList()
  105. );
  106. return bless %self, $class;
  107. }
  108. ##
  109. # int $ObjectList->add(Object item)
  110. # item: The item to add.
  111. # Returns:  The index of the item in this list. Note that this index
  112. #           must not be treated like an index in a regular Perl array:
  113. #           it may be greater than $self->size(). See the overview for
  114. #           information.
  115. # Requires: defined($item)
  116. # Ensures:  $self->size() == $old->size() + 1
  117. #
  118. # Add an item to this list. This will trigger an onAdd event, after the
  119. # item has been added.
  120. #
  121. # Note that subclasses of ObjectList may have further preconditions.
  122. sub add {
  123. my ($self, $item) = @_;
  124. assert(defined $item) if DEBUG;
  125. assert(Scalar::Util::blessed $item) if DEBUG;
  126. my $index = _findEmptyIndex($self->{OL_items});
  127. $self->{OL_items}[$index] = $item;
  128. splice(@{$self->{OL_cItems}}, $index, 0, $item);
  129. $self->{OL_onAdd}->call($self, [$item, $index]);
  130. return $index;
  131. }
  132. # Find the first empty index in the specified array.
  133. sub _findEmptyIndex {
  134. my ($items) = @_;
  135. for (my $i = 0; $i < @{$items}; $i++) {
  136. return $i if (!exists $items->[$i]);
  137. }
  138. return @{$items};
  139. }
  140. ##
  141. # Object $ObjectList->get(int index)
  142. # index: An index, as returned by $ObjectList->add()
  143. # Requires: $index >= 0
  144. #
  145. # Returns the item at the specified index, or undef
  146. # if there is no item at the specified index.
  147. #
  148. # Note: you must not use get() and size() to iterate through the list.
  149. # Use getItems() instead. See the overview for more information.
  150. sub get {
  151. my ($self, $index) = @_;
  152. assert($index >= 0) if DEBUG;
  153. return $self->{OL_items}[$index];
  154. }
  155. ##
  156. # int $ObjectList->find(Object item)
  157. # Requires: defined($item)
  158. # Ensures:
  159. #     result >= -1
  160. #     if result != -1: $self->get(result) == $item
  161. #
  162. # Returns the index of the first occurence of $item, or -1 if not found.
  163. sub find {
  164. my ($self, $item) = @_;
  165. assert(defined $item) if DEBUG;
  166. assert(Scalar::Util::blessed $item) if DEBUG;
  167. return _findItem($self->{OL_items}, $item);
  168. }
  169. # Returns the index of the first occurence of $item, or -1 if not found.
  170. sub _findItem {
  171. my ($array, $item) = @_;
  172. for (my $i = 0; $i < @{$array}; $i++) {
  173. next if (!exists $array->[$i]);
  174. return $i if ($array->[$i] == $item);
  175. }
  176. return -1;
  177. }
  178. ##
  179. # boolean $ObjectList->remove(Object item)
  180. # item: The item to remove.
  181. # Returns: Whether $item was in the list.
  182. # Requires: defined($item)
  183. # Ensures:  if result: $self->size() == $old->size() - 1
  184. #
  185. # Remove the first occurance of $item from this list. This will trigger
  186. # an onRemove event, after the item has been removed.
  187. sub remove {
  188. my ($self, $item) = @_;
  189. assert(defined $item) if DEBUG;
  190. assert(Scalar::Util::blessed $item) if DEBUG;
  191. my $index = _findItem($self->{OL_items}, $item);
  192. if ($index == -1) {
  193. return 0;
  194. } else {
  195. delete $self->{OL_items}[$index];
  196. my $cItemIndex = _findItem($self->{OL_cItems}, $item);
  197. splice(@{$self->{OL_cItems}}, $cItemIndex, 1);
  198. $self->{OL_onRemove}->call($self, [$item, $index]);
  199. return 1;
  200. }
  201. }
  202. ##
  203. # void $ObjectList->clear()
  204. # Ensures: $self->size() == 0
  205. #
  206. # Removes all items in this list. This will trigger the following events:
  207. # `l
  208. # - An onClearBegin event before the clearing begins.
  209. # - An onClearEnd event after the entire list has been cleared.
  210. # `l`
  211. sub clear {
  212. my ($self) = @_;
  213. $self->{OL_onClearBegin}->call($self);
  214. $self->doClear();
  215. $self->{OL_onClearEnd}->call($self);
  216. }
  217. ##
  218. # protected void $ObjectList->doClear()
  219. # Ensures: $self->size() == 0
  220. #
  221. # Clears all items in the list. This method is called by $ObjectList->clear(),
  222. # after the onClearBegin event is sent, and before the onClearEnd event is sent.
  223. # This method must not be called directly, and is supposed to be overloaded by
  224. # subclasses that want to implement different clearing behavior.
  225. sub doClear {
  226. my ($self) = @_;
  227. $self->{OL_items} = [];
  228. $self->{OL_cItems} = [];
  229. }
  230. ##
  231. # int $ObjectList->size()
  232. # Ensures: result >= 0
  233. #
  234. # Returns the number of items.
  235. #
  236. # Note: you must not use get() and size() to iterate through the list.
  237. # Use getItems() instead. See the overview for more information.
  238. sub size {
  239. return scalar @{$_[0]->{OL_cItems}};
  240. }
  241. ##
  242. # Array<Object>* $ObjectList->getItems()
  243. # Ensures:
  244. #     defined($result)
  245. #     @{$result} == $self->size()
  246. #     for all $k in @{$result}:
  247. #         defined($k)
  248. #
  249. # Returns a reference to an array, which contains all items in this list.
  250. # It is safe to remove items during iteration.
  251. sub getItems {
  252. return $_[0]->{OL_cItems};
  253. }
  254. ##
  255. # CallbackList $ObjectList->onAdd()
  256. # Ensures: defined(result)
  257. #
  258. # Returns the onAdd event callback list. This event is triggered after an
  259. # item has been added. The callback's argument is a reference to an array,
  260. # with the 0th element being the item that was added, and the 1st element the
  261. # index of that item.
  262. sub onAdd {
  263. return $_[0]->{OL_onAdd};
  264. }
  265. ##
  266. # CallbackList $ObjectList->onRemove()
  267. # Ensures: defined(result)
  268. #
  269. # Returns the onRemove event callback list. This event is triggered
  270. # after an item has been removed. The callback's argument is a reference to an
  271. # array, with the 0th element being the item that was deleted, and the 1st
  272. # element the index of that item.
  273. #
  274. # This event is not called when the list is cleared.
  275. sub onRemove {
  276. return $_[0]->{OL_onRemove};
  277. }
  278. ##
  279. # CallbackList $ObjectList->onClearBegin()
  280. # Ensures: defined(result)
  281. #
  282. # Returns the onClearBegin event callback list.
  283. sub onClearBegin {
  284. return $_[0]->{OL_onClearBegin};
  285. }
  286. ##
  287. # CallbackList $ObjectList->onClearEnd()
  288. # Ensures: defined(result)
  289. #
  290. # Returns the onClearEnd event callback list.
  291. sub onClearEnd {
  292. return $_[0]->{OL_onClearEnd};
  293. }
  294. ##
  295. # void $ObjectList->checkValidity()
  296. #
  297. # Check whether the internal invariants are correct.
  298. sub checkValidity {
  299. my ($self) = @_;
  300. my $items = $self->{OL_items};
  301. my $cItems = $self->{OL_cItems};
  302. assert(defined $items);
  303. assert(defined $cItems);
  304. assert(@{$cItems} <= @{$items});
  305. for (my $i = 0; $i < @{$cItems}; $i++) {
  306. assert(exists $cItems->[$i]);
  307. }
  308. assert(defined $self->{OL_onAdd});
  309. assert(defined $self->{OL_onRemove});
  310. assert(defined $self->{OL_onClearBegin});
  311. assert(defined $self->{OL_onClearEnd});
  312. }
  313. 1;