Advertisement
Guest User

Untitled

a guest
Jul 30th, 2015
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.77 KB | None | 0 0
  1. /**
  2. * PhysicalCraftingRecipe matches blocks laid in a pattern horizontally in the world.
  3. * This class can be used to trigger events when the player constructs shapes on the
  4. * ground.
  5. */
  6. public class PhysicalCraftingRecipe {
  7.  
  8. public final Material[][] pattern;
  9. public final byte[][] data;
  10. public final Set<Material> usedMaterials = new HashSet<>();
  11.  
  12. /**
  13. * Creates a PhysicalCraftingRecipe from a 2D pattern of Materials. The pattern must
  14. * be rectangular - all rows must be the same length.
  15. *
  16. * @param pattern
  17. * The rectangle of Materials to match.
  18. */
  19. public PhysicalCraftingRecipe(Material[][] pattern) {
  20. this(pattern, bytesFromPattern(pattern));
  21. }
  22.  
  23. /**
  24. * Creates a PhysicalCraftingRecipe from a 2D pattern of Materials and data values. The pattern must
  25. * be rectangular - all rows must be the same length. Data must be the same dimensions as pattern.
  26. * A data value of -1 matches all data values.
  27. *
  28. * @param pattern
  29. * The rectangle of Materials to match.
  30. * @param data
  31. * The rectangle block data bytes to match.
  32. */
  33. public PhysicalCraftingRecipe(Material[][] pattern, byte[][] data) {
  34. Validate.notEmpty(pattern, "pattern cannot be null or empty");
  35. Validate.notEmpty(data, "data cannot be null or empty");
  36.  
  37. // Validate that pattern and data are the same 'shape'
  38. if (pattern.length != data.length) {
  39. throw new IllegalArgumentException("pattern and data must be the same 'shape'");
  40. }
  41. for (int i = 0; i < pattern.length; i++) {
  42. if (pattern[i].length != data[i].length) {
  43. throw new IllegalArgumentException("pattern and data must be the same 'shape'");
  44. }
  45. }
  46.  
  47. this.pattern = pattern;
  48. this.data = data;
  49. for (Material[] row : pattern) {
  50. Collections.addAll(usedMaterials, row);
  51. }
  52. }
  53.  
  54. private static byte[][] bytesFromPattern(Material[][] pattern) {
  55. Validate.notEmpty(pattern, "pattern cannot be null or empty");
  56. byte[][] bytes = new byte[pattern.length][];
  57. for (int i = 0; i < bytes.length; i++) {
  58. bytes[i] = new byte[pattern[i].length];
  59. Arrays.fill(bytes[i], (byte) -1);
  60. }
  61. return bytes;
  62. }
  63.  
  64. /**
  65. * Constructs a PhysicalCraftingRecipe from an array of strings. Each character in the array represents one
  66. * combination of material/data specified in the materialDataMap. The materialDataMap map entries start with the
  67. * name of the associated material, followed by an optional data value separated by a colon.
  68. *
  69. * @param rows
  70. * The characters making up the crafting recipe
  71. * @param materialDataMap
  72. * A mapping between the crafting recipe characters and materials/data.
  73. * @return
  74. */
  75. public static PhysicalCraftingRecipe fromStringRepresentation(String[] rows, Map<Character, String> materialDataMap) {
  76. Validate.notEmpty(rows, "rows cannot be null or empty");
  77. Validate.notEmpty(materialDataMap, "materialMap cannot be null or empty");
  78.  
  79. // Break up materialDataMap into materialMap and dataMap
  80. Map<Character, Material> materialMap = new HashMap<>();
  81. Map<Character, Byte> dataMap = new HashMap<>();
  82. for (Character c : materialDataMap.keySet()) {
  83. String s = materialDataMap.get(c);
  84. String[] splits = s.split(":", 2);
  85. Material m = Material.matchMaterial(splits[0]);
  86. if (m == null) {
  87. throw new IllegalArgumentException(splits[0] + " is not a valid material");
  88. }
  89. byte b = -1;
  90. if (splits.length > 1) {
  91. try {
  92. b = Byte.parseByte(splits[1]);
  93. } catch (NumberFormatException e) {
  94. throw new IllegalArgumentException(splits[1] + " is not a valid data byte");
  95. }
  96. }
  97. materialMap.put(c, m);
  98. dataMap.put(c, b);
  99. }
  100.  
  101. return fromStringRepresentation(rows, materialMap, dataMap);
  102. }
  103.  
  104. /**
  105. * Constructs a PhysicalCraftingRecipe from an array of strings. Each character in the array represents one
  106. * combination of material/data encoded in materialMap and dataMap. Data values of -1 match any material value.
  107. *
  108. * @param rows
  109. * The characters making up the crafting recipe
  110. * @param materialMap
  111. * The materials to match in the crafting recipe
  112. * @param dataMap
  113. * The data values to match in the crafting recipe
  114. * @return
  115. */
  116. public static PhysicalCraftingRecipe fromStringRepresentation(String[] rows, Map<Character, Material> materialMap, Map<Character, Byte> dataMap) {
  117. // Sanity check the input
  118. Validate.notEmpty(rows, "rows cannot be null or empty");
  119. Validate.notEmpty(materialMap, "materialMap cannot be null or empty");
  120. Validate.notEmpty(dataMap, "dataMap cannot be null or empty");
  121. Validate.isTrue(materialMap.size() == dataMap.size(), "materialMap and dataMap must be the same length");
  122. materialMap.put(' ', null);
  123.  
  124. // Validate the relationship between rows and maps
  125. int rowLength = rows[0].length();
  126. for (String row : rows) {
  127. if (row.length() != rowLength) {
  128. throw new IllegalArgumentException("all strings in rows must be the same length");
  129. }
  130. for (char c : row.toCharArray()) {
  131. if (!materialMap.containsKey(c)) {
  132. throw new IllegalArgumentException("all characters in rows must be in materialMap");
  133. }
  134. if (!dataMap.containsKey(c)) {
  135. throw new IllegalArgumentException("all characters in rows must be in dataMap");
  136. }
  137. }
  138. }
  139.  
  140. // Construct the pattern
  141. Material[][] pattern = new Material[rows.length][rowLength];
  142. byte[][] data = new byte[rows.length][rowLength];
  143. for (int i = 0; i < rows.length; i++) {
  144. for (int j = 0; j < rowLength; j++) {
  145. char c = rows[i].toCharArray()[j];
  146. pattern[i][j] = materialMap.get(c);
  147. data[i][j] = dataMap.get(c);
  148. }
  149. }
  150.  
  151. return new PhysicalCraftingRecipe(pattern, data);
  152. }
  153.  
  154. /**
  155. * Determines if this PhysicalCraftingRecipe matches the blocks in the world.
  156. *
  157. * @param lastPlaced
  158. * A starting point for evaluating this recipe.
  159. * @return
  160. */
  161. public boolean matches(Block lastPlaced) {
  162. Validate.notNull(lastPlaced, "lastPlaced cannot be null");
  163.  
  164. // Verify that the block placed could be part of the pattern
  165. if (!usedMaterials.contains(lastPlaced.getType())) {
  166. return false;
  167. }
  168. // Scan the world looking for a match
  169. int size = Math.max(pattern.length, pattern[0].length);
  170. int patternMatchCount = 0;
  171. int y = lastPlaced.getY();
  172. for (int x = lastPlaced.getX() - size + 1; x <= lastPlaced.getX(); x++) {
  173. outer:
  174. for (int z = lastPlaced.getZ() - size + 1; z <= lastPlaced.getZ(); z++) {
  175. boolean allRowsPass = true;
  176. inner:
  177. for (int px = 0; px < pattern.length; px++) {
  178. for (int pz = 0; pz < pattern[0].length; pz++) {
  179. Block b = lastPlaced.getWorld().getBlockAt(x + px, y, z + pz);
  180. if (pattern[px][pz] != null && b.getType() != pattern[px][pz]) {
  181. allRowsPass = false;
  182. break inner;
  183. } else if (data[px][pz] != -1 && b.getData() != data[px][pz]) {
  184. allRowsPass = false;
  185. break inner;
  186. }
  187. }
  188. }
  189. if (allRowsPass) {
  190. patternMatchCount++;
  191. break;
  192. }
  193.  
  194. allRowsPass = true;
  195. inner:
  196. for (int px = 0; px < pattern.length; px++) {
  197. for (int pz = 0; pz < pattern[0].length; pz++) {
  198. Block b = lastPlaced.getWorld().getBlockAt(x + px, y, z + pz);
  199. if (pattern[pattern.length - 1 - px][pz] != null && b.getType() != pattern[pattern.length - 1 - px][pz]) {
  200. allRowsPass = false;
  201. break inner;
  202. } else if (data[pattern.length - 1 - px][pz] != -1 && b.getData() != data[pattern.length - 1 - px][pz]) {
  203. allRowsPass = false;
  204. break inner;
  205. }
  206. }
  207. }
  208. if (allRowsPass) {
  209. patternMatchCount++;
  210. break;
  211. }
  212.  
  213. allRowsPass = true;
  214. inner:
  215. for (int px = 0; px < pattern.length; px++) {
  216. for (int pz = 0; pz < pattern[0].length; pz++) {
  217. Block b = lastPlaced.getWorld().getBlockAt(x + px, y, z + pz);
  218. if (pattern[px][pattern[0].length - 1 - pz] != null && b.getType() != pattern[px][pattern[0].length - 1 - pz]) {
  219. allRowsPass = false;
  220. break inner;
  221. } else if (data[px][pattern[0].length - 1 - pz] != -1 && b.getData() != data[px][pattern[0].length - 1 - pz]) {
  222. allRowsPass = false;
  223. break inner;
  224. }
  225. }
  226. }
  227. if (allRowsPass) {
  228. patternMatchCount++;
  229. break;
  230. }
  231.  
  232. allRowsPass = true;
  233. inner:
  234. for (int px = 0; px < pattern.length; px++) {
  235. for (int pz = 0; pz < pattern[0].length; pz++) {
  236. Block b = lastPlaced.getWorld().getBlockAt(x + px, y, z + pz);
  237. if (pattern[pattern.length - 1 - px][pattern[0].length - 1 - pz] != null && b.getType() != pattern[pattern.length - 1 - px][pattern[0].length - 1 - pz]) {
  238. allRowsPass = false;
  239. break inner;
  240. } else if (data[pattern.length - 1 - px][pattern[0].length - 1 - pz] != -1 && b.getData() != data[pattern.length - 1 - px][pattern[0].length - 1 - pz]) {
  241. allRowsPass = false;
  242. break inner;
  243. }
  244. }
  245. }
  246. if (allRowsPass) {
  247. patternMatchCount++;
  248. break;
  249. }
  250. }
  251. }
  252. return patternMatchCount == 1;
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement