/common/buildcraft/lib/list/ListHandler.java

https://github.com/2xsaiko/BuildCraft · Java · 290 lines · 245 code · 35 blank · 10 comment · 78 complexity · 2e3babd1ef527befd1cd4ce300cf122b MD5 · raw file

  1. /*
  2. * Copyright (c) 2017 SpaceToad and the BuildCraft team
  3. * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
  4. * distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/
  5. */
  6. package buildcraft.lib.list;
  7. import java.util.ArrayList;
  8. import java.util.Collections;
  9. import java.util.List;
  10. import javax.annotation.Nonnull;
  11. import net.minecraft.creativetab.CreativeTabs;
  12. import net.minecraft.item.Item;
  13. import net.minecraft.item.ItemStack;
  14. import net.minecraft.nbt.NBTTagCompound;
  15. import net.minecraft.nbt.NBTTagList;
  16. import net.minecraft.util.NonNullList;
  17. import net.minecraftforge.fml.common.registry.ForgeRegistries;
  18. import net.minecraftforge.fml.relauncher.Side;
  19. import net.minecraftforge.fml.relauncher.SideOnly;
  20. import buildcraft.api.lists.ListMatchHandler;
  21. import buildcraft.api.lists.ListRegistry;
  22. import buildcraft.lib.misc.NBTUtilBC;
  23. import buildcraft.lib.misc.StackUtil;
  24. public final class ListHandler {
  25. public static final int WIDTH = 9;
  26. public static final int HEIGHT = 2;
  27. public static class Line {
  28. public final NonNullList<ItemStack> stacks;
  29. public boolean precise, byType, byMaterial;
  30. public Line() {
  31. stacks = NonNullList.withSize(WIDTH, StackUtil.EMPTY);
  32. }
  33. /** Checks to see if this line is completely blank, and no data would be lost if this line was not saved. */
  34. public boolean isDefault() {
  35. if (precise || byType || byMaterial) return false;
  36. return !hasItems();
  37. }
  38. /** Checks to see if this line has any items */
  39. public boolean hasItems() {
  40. for (ItemStack stack : stacks) {
  41. if (!stack.isEmpty()) return true;
  42. }
  43. return false;
  44. }
  45. public boolean isOneStackMode() {
  46. return byType || byMaterial;
  47. }
  48. public boolean getOption(int id) {
  49. return id == 0 ? precise : (id == 1 ? byType : byMaterial);
  50. }
  51. public void toggleOption(int id) {
  52. if (!byType && !byMaterial && (id == 1 || id == 2)) {
  53. for (int i = 1; i < stacks.size(); i++) {
  54. stacks.set(i, StackUtil.EMPTY);
  55. }
  56. }
  57. switch (id) {
  58. case 0:
  59. precise = !precise;
  60. break;
  61. case 1:
  62. byType = !byType;
  63. break;
  64. case 2:
  65. byMaterial = !byMaterial;
  66. break;
  67. }
  68. }
  69. public boolean matches(@Nonnull ItemStack target) {
  70. if (byType || byMaterial) {
  71. if (stacks.get(0).isEmpty()) {
  72. return false;
  73. }
  74. List<ListMatchHandler> handlers = ListRegistry.getHandlers();
  75. ListMatchHandler.Type type = getSortingType();
  76. for (ListMatchHandler h : handlers) {
  77. if (h.matches(type, stacks.get(0), target, precise)) {
  78. return true;
  79. }
  80. }
  81. } else {
  82. for (ItemStack s : stacks) {
  83. if (s != null && StackUtil.isMatchingItem(s, target, true, precise)) {
  84. // If precise, re-check damage
  85. if (!precise || s.getItemDamage() == target.getItemDamage()) {
  86. return true;
  87. }
  88. }
  89. }
  90. }
  91. return false;
  92. }
  93. public ListMatchHandler.Type getSortingType() {
  94. return byType ? (byMaterial ? ListMatchHandler.Type.CLASS : ListMatchHandler.Type.TYPE) : ListMatchHandler.Type.MATERIAL;
  95. }
  96. public static Line fromNBT(NBTTagCompound data) {
  97. Line line = new Line();
  98. if (data != null && data.hasKey("st")) {
  99. NBTTagList l = data.getTagList("st", 10);
  100. for (int i = 0; i < l.tagCount(); i++) {
  101. line.stacks.set(i, new ItemStack(l.getCompoundTagAt(i)));
  102. }
  103. line.precise = data.getBoolean("Fp");
  104. line.byType = data.getBoolean("Ft");
  105. line.byMaterial = data.getBoolean("Fm");
  106. }
  107. return line;
  108. }
  109. public NBTTagCompound toNBT() {
  110. NBTTagCompound data = new NBTTagCompound();
  111. NBTTagList stackList = new NBTTagList();
  112. for (ItemStack stack1 : stacks) {
  113. NBTTagCompound stack = new NBTTagCompound();
  114. if (stack1 != null) {
  115. stack1.writeToNBT(stack);
  116. }
  117. stackList.appendTag(stack);
  118. }
  119. data.setTag("st", stackList);
  120. data.setBoolean("Fp", precise);
  121. data.setBoolean("Ft", byType);
  122. data.setBoolean("Fm", byMaterial);
  123. return data;
  124. }
  125. public void setStack(int slotIndex, @Nonnull ItemStack stack) {
  126. if (slotIndex == 0 || (!byType && !byMaterial)) {
  127. if (stack.isEmpty()) {
  128. stacks.set(slotIndex, StackUtil.EMPTY);
  129. } else {
  130. stack = stack.copy();
  131. stack.setCount(1);
  132. stacks.set(slotIndex, stack);
  133. }
  134. }
  135. }
  136. @Nonnull
  137. public ItemStack getStack(int i) {
  138. if (i < 0 || i >= stacks.size()) {
  139. return StackUtil.EMPTY;
  140. } else {
  141. return stacks.get(i);
  142. }
  143. }
  144. @SideOnly(Side.CLIENT)
  145. public NonNullList<ItemStack> getExamples() {
  146. ItemStack firstStack = stacks.get(0);
  147. if (firstStack.isEmpty()) {
  148. return NonNullList.withSize(0, StackUtil.EMPTY);
  149. }
  150. NonNullList<ItemStack> stackList = NonNullList.create();
  151. List<ListMatchHandler> handlers = ListRegistry.getHandlers();
  152. List<ListMatchHandler> handlersCustom = new ArrayList<>();
  153. ListMatchHandler.Type type = getSortingType();
  154. for (ListMatchHandler h : handlers) {
  155. if (h.isValidSource(type, firstStack)) {
  156. NonNullList<ItemStack> examples = h.getClientExamples(type, firstStack);
  157. if (examples != null) {
  158. stackList.addAll(examples);
  159. } else {
  160. handlersCustom.add(h);
  161. }
  162. }
  163. }
  164. if (handlersCustom.size() > 0) {
  165. for (Item i : ForgeRegistries.ITEMS) {
  166. NonNullList<ItemStack> examples = NonNullList.create();
  167. i.getSubItems(CreativeTabs.MISC, examples);
  168. for (ItemStack s : examples) {
  169. for (ListMatchHandler mh : handlersCustom) {
  170. if (mh.matches(type, firstStack, s, false)) {
  171. stackList.add(s);
  172. break;
  173. }
  174. }
  175. }
  176. }
  177. }
  178. Collections.shuffle(stackList);
  179. return stackList;
  180. }
  181. }
  182. private ListHandler() {
  183. }
  184. public static boolean hasItems(@Nonnull ItemStack stack) {
  185. if (!stack.hasTagCompound()) return false;
  186. for (Line l : getLines(stack)) {
  187. if (l.hasItems()) return true;
  188. }
  189. return false;
  190. }
  191. public static boolean isDefault(@Nonnull ItemStack stack) {
  192. if (!stack.hasTagCompound()) return true;
  193. for (Line l : getLines(stack)) {
  194. if (!l.isDefault()) return false;
  195. }
  196. return true;
  197. }
  198. public static Line[] getLines(@Nonnull ItemStack item) {
  199. NBTTagCompound data = NBTUtilBC.getItemData(item);
  200. if (data.hasKey("written") && data.hasKey("lines")) {
  201. NBTTagList list = data.getTagList("lines", 10);
  202. Line[] lines = new Line[list.tagCount()];
  203. for (int i = 0; i < lines.length; i++) {
  204. lines[i] = Line.fromNBT(list.getCompoundTagAt(i));
  205. }
  206. return lines;
  207. } else {
  208. Line[] lines = new Line[HEIGHT];
  209. for (int i = 0; i < lines.length; i++) {
  210. lines[i] = new Line();
  211. }
  212. return lines;
  213. }
  214. }
  215. public static void saveLines(@Nonnull ItemStack stackList, Line[] lines) {
  216. boolean hasLine = false;
  217. for (Line l : lines) {
  218. if (!l.isDefault()) {
  219. hasLine = true;
  220. break;
  221. }
  222. }
  223. if (hasLine) {
  224. NBTTagCompound data = NBTUtilBC.getItemData(stackList);
  225. data.setBoolean("written", true);
  226. NBTTagList lineList = new NBTTagList();
  227. for (Line saving : lines) {
  228. lineList.appendTag(saving.toNBT());
  229. }
  230. data.setTag("lines", lineList);
  231. } else if (stackList.hasTagCompound()) {
  232. NBTTagCompound data = NBTUtilBC.getItemData(stackList);
  233. // No non-default lines, we can remove the old NBT data
  234. data.removeTag("written");
  235. data.removeTag("lines");
  236. if (data.hasNoTags()) {
  237. // We can safely remove the
  238. stackList.setTagCompound(null);
  239. }
  240. }
  241. }
  242. public static boolean matches(@Nonnull ItemStack stackList, @Nonnull ItemStack item) {
  243. NBTTagCompound data = NBTUtilBC.getItemData(stackList);
  244. if (data.hasKey("written") && data.hasKey("lines")) {
  245. NBTTagList list = data.getTagList("lines", 10);
  246. for (int i = 0; i < list.tagCount(); i++) {
  247. Line line = Line.fromNBT(list.getCompoundTagAt(i));
  248. if (line.matches(item)) {
  249. return true;
  250. }
  251. }
  252. }
  253. return false;
  254. }
  255. }