PageRenderTime 87ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/newcode/src/com/prupe/mcpatcher/ctm/TileOverride.java

https://bitbucket.org/SevenBits/mcpatcher
Java | 507 lines | 451 code | 53 blank | 3 comment | 182 complexity | d352465b986202861f5e0ec067c02897 MD5 | raw file
  1. package com.prupe.mcpatcher.ctm;
  2. import com.prupe.mcpatcher.MCLogger;
  3. import com.prupe.mcpatcher.MCPatcherUtils;
  4. import com.prupe.mcpatcher.TexturePackAPI;
  5. import com.prupe.mcpatcher.TileLoader;
  6. import com.prupe.mcpatcher.mal.biome.BiomeAPI;
  7. import com.prupe.mcpatcher.mal.block.BlockAPI;
  8. import com.prupe.mcpatcher.mal.block.BlockAndMetadata;
  9. import com.prupe.mcpatcher.mal.block.RenderPassAPI;
  10. import net.minecraft.src.Block;
  11. import net.minecraft.src.IBlockAccess;
  12. import net.minecraft.src.Icon;
  13. import net.minecraft.src.ResourceLocation;
  14. import java.util.*;
  15. import java.util.regex.Matcher;
  16. import java.util.regex.Pattern;
  17. import static com.prupe.mcpatcher.ctm.BlockOrientation.*;
  18. abstract class TileOverride implements ITileOverride {
  19. private static final MCLogger logger = MCLogger.getLogger(MCPatcherUtils.CONNECTED_TEXTURES, "CTM");
  20. private static final int META_MASK = 0xffff;
  21. private static final int CONNECT_BY_BLOCK = 0;
  22. private static final int CONNECT_BY_TILE = 1;
  23. private static final int CONNECT_BY_MATERIAL = 2;
  24. private final ResourceLocation propertiesFile;
  25. private final String baseFilename;
  26. private final TileLoader tileLoader;
  27. private final int renderPass;
  28. private final int weight;
  29. private final Map<Block, Integer> matchBlocks;
  30. private final Set<String> matchTiles;
  31. private final int defaultMetaMask;
  32. private final int faces;
  33. private final int connectType;
  34. private final boolean innerSeams;
  35. private final BitSet biomes;
  36. private final BitSet height;
  37. private final List<ResourceLocation> tileNames = new ArrayList<ResourceLocation>();
  38. protected Icon[] icons;
  39. private boolean disabled;
  40. private int warnCount;
  41. private int matchMetadata;
  42. static TileOverride create(ResourceLocation propertiesFile, TileLoader tileLoader) {
  43. if (propertiesFile == null) {
  44. return null;
  45. }
  46. Properties properties = TexturePackAPI.getProperties(propertiesFile);
  47. if (properties == null) {
  48. return null;
  49. }
  50. String method = properties.getProperty("method", "default").trim().toLowerCase();
  51. TileOverride override = null;
  52. if (method.equals("default") || method.equals("glass") || method.equals("ctm")) {
  53. override = new TileOverrideImpl.CTM(propertiesFile, properties, tileLoader);
  54. } else if (method.equals("random")) {
  55. override = new TileOverrideImpl.Random1(propertiesFile, properties, tileLoader);
  56. if (override.getNumberOfTiles() == 1) {
  57. override = new TileOverrideImpl.Fixed(propertiesFile, properties, tileLoader);
  58. }
  59. } else if (method.equals("fixed") || method.equals("static")) {
  60. override = new TileOverrideImpl.Fixed(propertiesFile, properties, tileLoader);
  61. } else if (method.equals("bookshelf") || method.equals("horizontal")) {
  62. override = new TileOverrideImpl.Horizontal(propertiesFile, properties, tileLoader);
  63. } else if (method.equals("horizontal+vertical") || method.equals("h+v")) {
  64. override = new TileOverrideImpl.HorizontalVertical(propertiesFile, properties, tileLoader);
  65. } else if (method.equals("vertical")) {
  66. override = new TileOverrideImpl.Vertical(propertiesFile, properties, tileLoader);
  67. } else if (method.equals("vertical+horizontal") || method.equals("v+h")) {
  68. override = new TileOverrideImpl.VerticalHorizontal(propertiesFile, properties, tileLoader);
  69. } else if (method.equals("sandstone") || method.equals("top")) {
  70. override = new TileOverrideImpl.Top(propertiesFile, properties, tileLoader);
  71. } else if (method.equals("repeat") || method.equals("pattern")) {
  72. override = new TileOverrideImpl.Repeat(propertiesFile, properties, tileLoader);
  73. } else {
  74. logger.error("%s: unknown method \"%s\"", propertiesFile, method);
  75. }
  76. if (override != null && !override.disabled) {
  77. String status = override.checkTileMap();
  78. if (status != null) {
  79. override.error("invalid %s tile map: %s", override.getMethod(), status);
  80. }
  81. }
  82. return override == null || override.disabled ? null : override;
  83. }
  84. protected TileOverride(ResourceLocation propertiesFile, Properties properties, TileLoader tileLoader) {
  85. this.propertiesFile = propertiesFile;
  86. String texturesDirectory = propertiesFile.getPath().replaceFirst("/[^/]*$", "");
  87. baseFilename = propertiesFile.getPath().replaceFirst(".*/", "").replaceFirst("\\.properties$", "");
  88. this.tileLoader = tileLoader;
  89. String renderPassStr = MCPatcherUtils.getStringProperty(properties, "renderPass", "");
  90. renderPass = RenderPassAPI.instance.parseRenderPass(renderPassStr);
  91. if (renderPassStr.matches("\\d+") && renderPass >= 0 && renderPass <= RenderPassAPI.MAX_EXTRA_RENDER_PASS) {
  92. warn("renderPass=%s is deprecated, use renderPass=%s instead",
  93. renderPassStr, RenderPassAPI.instance.getRenderPassName(renderPass)
  94. );
  95. }
  96. loadIcons(properties);
  97. if (tileNames.isEmpty()) {
  98. error("no images found in %s/", texturesDirectory);
  99. }
  100. String value;
  101. if (baseFilename.matches("block\\d+.*")) {
  102. value = baseFilename.replaceFirst("block(\\d+).*", "$1");
  103. } else {
  104. value = "";
  105. }
  106. matchBlocks = getBlockList(
  107. MCPatcherUtils.getStringProperty(properties, "matchBlocks", value),
  108. MCPatcherUtils.getStringProperty(properties, "metadata", "")
  109. );
  110. matchTiles = getTileList(properties, "matchTiles");
  111. if (matchBlocks.isEmpty() && matchTiles.isEmpty()) {
  112. matchTiles.add(baseFilename);
  113. }
  114. int bits = 0;
  115. for (int i : MCPatcherUtils.parseIntegerList(MCPatcherUtils.getStringProperty(properties, "metadata", "0-15"), 0, 15)) {
  116. bits |= 1 << i;
  117. }
  118. defaultMetaMask = bits;
  119. int flags = 0;
  120. for (String val : properties.getProperty("faces", "all").trim().toLowerCase().split("\\s+")) {
  121. if (val.equals("bottom")) {
  122. flags |= (1 << BOTTOM_FACE);
  123. } else if (val.equals("top")) {
  124. flags |= (1 << TOP_FACE);
  125. } else if (val.equals("north")) {
  126. flags |= (1 << NORTH_FACE);
  127. } else if (val.equals("south")) {
  128. flags |= (1 << SOUTH_FACE);
  129. } else if (val.equals("east")) {
  130. flags |= (1 << EAST_FACE);
  131. } else if (val.equals("west")) {
  132. flags |= (1 << WEST_FACE);
  133. } else if (val.equals("side") || val.equals("sides")) {
  134. flags |= (1 << NORTH_FACE) | (1 << SOUTH_FACE) | (1 << EAST_FACE) | (1 << WEST_FACE);
  135. } else if (val.equals("all")) {
  136. flags = -1;
  137. }
  138. }
  139. faces = flags;
  140. String connectType1 = properties.getProperty("connect", "").trim().toLowerCase();
  141. if (connectType1.equals("")) {
  142. connectType = matchTiles.isEmpty() ? CONNECT_BY_BLOCK : CONNECT_BY_TILE;
  143. } else if (connectType1.equals("block")) {
  144. connectType = CONNECT_BY_BLOCK;
  145. } else if (connectType1.equals("tile")) {
  146. connectType = CONNECT_BY_TILE;
  147. } else if (connectType1.equals("material")) {
  148. connectType = CONNECT_BY_MATERIAL;
  149. } else {
  150. error("invalid connect type %s", connectType1);
  151. connectType = CONNECT_BY_BLOCK;
  152. }
  153. innerSeams = MCPatcherUtils.getBooleanProperty(properties, "innerSeams", false);
  154. String biomeList = properties.getProperty("biomes", "");
  155. if (biomeList.isEmpty()) {
  156. biomes = null;
  157. } else {
  158. biomes = new BitSet();
  159. BiomeAPI.parseBiomeList(biomeList, biomes);
  160. }
  161. height = BiomeAPI.getHeightListProperty(properties, "");
  162. if (renderPass > RenderPassAPI.MAX_EXTRA_RENDER_PASS) {
  163. error("invalid renderPass %s", renderPassStr);
  164. } else if (renderPass >= 0 && !matchTiles.isEmpty()) {
  165. error("renderPass=%s must be block-based not tile-based", RenderPassAPI.instance.getRenderPassName(renderPass));
  166. }
  167. weight = MCPatcherUtils.getIntProperty(properties, "weight", 0);
  168. }
  169. private boolean addIcon(ResourceLocation resource) {
  170. tileNames.add(resource);
  171. return tileLoader.preloadTile(resource, renderPass > RenderPassAPI.MAX_BASE_RENDER_PASS);
  172. }
  173. private void loadIcons(Properties properties) {
  174. tileNames.clear();
  175. String tileList = properties.getProperty("tiles", "").trim();
  176. ResourceLocation blankResource = RenderPassAPI.instance.getBlankResource(renderPass);
  177. if (tileList.equals("")) {
  178. for (int i = 0; ; i++) {
  179. ResourceLocation resource = TileLoader.parseTileAddress(propertiesFile, String.valueOf(i), blankResource);
  180. if (!TexturePackAPI.hasResource(resource)) {
  181. break;
  182. }
  183. if (!addIcon(resource)) {
  184. break;
  185. }
  186. }
  187. } else {
  188. Pattern range = Pattern.compile("(\\d+)-(\\d+)");
  189. for (String token : tileList.split("\\s+")) {
  190. Matcher matcher = range.matcher(token);
  191. if (token.equals("")) {
  192. // nothing
  193. } else if (matcher.matches()) {
  194. try {
  195. int from = Integer.parseInt(matcher.group(1));
  196. int to = Integer.parseInt(matcher.group(2));
  197. for (int i = from; i <= to; i++) {
  198. ResourceLocation resource = TileLoader.parseTileAddress(propertiesFile, String.valueOf(i), blankResource);
  199. if (TexturePackAPI.hasResource(resource)) {
  200. addIcon(resource);
  201. } else {
  202. warn("could not find image %s", resource);
  203. tileNames.add(null);
  204. }
  205. }
  206. } catch (NumberFormatException e) {
  207. e.printStackTrace();
  208. }
  209. } else {
  210. ResourceLocation resource = TileLoader.parseTileAddress(propertiesFile, token, blankResource);
  211. if (resource == null) {
  212. tileNames.add(null);
  213. } else if (TexturePackAPI.hasResource(resource)) {
  214. addIcon(resource);
  215. } else {
  216. warn("could not find image %s", resource);
  217. tileNames.add(null);
  218. }
  219. }
  220. }
  221. }
  222. }
  223. private Map<Block, Integer> getBlockList(String property, String defaultMetadata) {
  224. Map<Block, BlockAndMetadata> blockMetas = new IdentityHashMap<Block, BlockAndMetadata>();
  225. for (String token : property.split("\\s+")) {
  226. if (token.equals("")) {
  227. // nothing
  228. } else if (token.matches("\\d+-\\d+")) {
  229. for (int id : MCPatcherUtils.parseIntegerList(token, 0, 65535)) {
  230. BlockAndMetadata blockMeta = BlockAndMetadata.parse(String.valueOf(id), defaultMetadata);
  231. if (blockMeta == null) {
  232. warn("unknown block id %d", id);
  233. } else {
  234. BlockAndMetadata oldBlockMeta = blockMetas.get(blockMeta.getBlock());
  235. blockMetas.put(blockMeta.getBlock(), blockMeta.combine(oldBlockMeta));
  236. }
  237. }
  238. } else {
  239. BlockAndMetadata blockMeta = BlockAndMetadata.parse(token, defaultMetadata);
  240. if (blockMeta == null) {
  241. warn("unknown block %s", token);
  242. } else {
  243. BlockAndMetadata oldBlockMeta = blockMetas.get(blockMeta.getBlock());
  244. blockMetas.put(blockMeta.getBlock(), blockMeta.combine(oldBlockMeta));
  245. }
  246. }
  247. }
  248. Map<Block, Integer> blocks = new IdentityHashMap<Block, Integer>();
  249. for (Map.Entry<Block, BlockAndMetadata> entry : blockMetas.entrySet()) {
  250. blocks.put(entry.getKey(), entry.getValue().getMetadataBits());
  251. }
  252. return blocks;
  253. }
  254. private Set<String> getTileList(Properties properties, String key) {
  255. Set<String> list = new HashSet<String>();
  256. String property = properties.getProperty(key, "");
  257. for (String token : property.split("\\s+")) {
  258. if (token.equals("")) {
  259. // nothing
  260. } else if (token.contains("/")) {
  261. if (!token.endsWith(".png")) {
  262. token += ".png";
  263. }
  264. ResourceLocation resource = TexturePackAPI.parseResourceLocation(propertiesFile, token);
  265. if (resource != null) {
  266. list.add(resource.toString());
  267. }
  268. } else {
  269. list.add(token);
  270. }
  271. }
  272. return list;
  273. }
  274. protected int getNumberOfTiles() {
  275. return tileNames.size();
  276. }
  277. String checkTileMap() {
  278. return null;
  279. }
  280. boolean requiresFace() {
  281. return false;
  282. }
  283. @Override
  284. public String toString() {
  285. return String.format("%s[%s] (%d tiles)", getMethod(), propertiesFile, getNumberOfTiles());
  286. }
  287. @Override
  288. public final void registerIcons() {
  289. icons = new Icon[tileNames.size()];
  290. for (int i = 0; i < icons.length; i++) {
  291. icons[i] = tileLoader.getIcon(tileNames.get(i));
  292. }
  293. }
  294. final void error(String format, Object... params) {
  295. if (propertiesFile != null) {
  296. logger.error(propertiesFile + ": " + format, params);
  297. }
  298. disabled = true;
  299. }
  300. final void warn(String format, Object... params) {
  301. if (propertiesFile != null && warnCount < 10) {
  302. logger.warning(propertiesFile + ": " + format, params);
  303. warnCount++;
  304. }
  305. }
  306. @Override
  307. final public boolean isDisabled() {
  308. return disabled;
  309. }
  310. @Override
  311. final public Set<Block> getMatchingBlocks() {
  312. return matchBlocks.keySet();
  313. }
  314. @Override
  315. final public Set<String> getMatchingTiles() {
  316. return matchTiles;
  317. }
  318. @Override
  319. final public int getRenderPass() {
  320. return renderPass;
  321. }
  322. @Override
  323. final public int getWeight() {
  324. return weight;
  325. }
  326. @Override
  327. public int compareTo(ITileOverride o) {
  328. int result = o.getWeight() - getWeight();
  329. if (result != 0) {
  330. return result;
  331. }
  332. if (o instanceof TileOverride) {
  333. return baseFilename.compareTo(((TileOverride) o).baseFilename);
  334. } else {
  335. return -1;
  336. }
  337. }
  338. final boolean shouldConnect(BlockOrientation blockOrientation, Icon icon, int relativeDirection) {
  339. return shouldConnect(blockOrientation, icon, blockOrientation.getOffset(relativeDirection));
  340. }
  341. final boolean shouldConnect(BlockOrientation blockOrientation, Icon icon, int blockFace, int relativeDirection) {
  342. return shouldConnect(blockOrientation, icon, blockOrientation.getOffset(blockFace, relativeDirection));
  343. }
  344. private boolean shouldConnect(BlockOrientation blockOrientation, Icon icon, int[] offset) {
  345. IBlockAccess blockAccess = blockOrientation.blockAccess;
  346. Block block = blockOrientation.block;
  347. int i = blockOrientation.i;
  348. int j = blockOrientation.j;
  349. int k = blockOrientation.k;
  350. int metadata = blockOrientation.metadata;
  351. i += offset[0];
  352. j += offset[1];
  353. k += offset[2];
  354. int neighborMeta = BlockAPI.getMetadataAt(blockAccess, i, j, k);
  355. Block neighbor = BlockAPI.getBlockAt(blockAccess, i, j, k);
  356. if (neighbor == null) {
  357. return false;
  358. }
  359. if (block == neighbor && matchMetadata != META_MASK && metadata != neighborMeta) {
  360. return false;
  361. }
  362. int blockFace = blockOrientation.blockFace;
  363. if (blockFace >= 0 && innerSeams) {
  364. int[] normal = NORMALS[blockFace];
  365. if (!BlockAPI.shouldSideBeRendered(neighbor, blockAccess, i + normal[0], j + normal[1], k + normal[2], blockFace)) {
  366. return false;
  367. }
  368. }
  369. switch (connectType) {
  370. case CONNECT_BY_BLOCK:
  371. return neighbor == block;
  372. case CONNECT_BY_TILE:
  373. return BlockAPI.getBlockIcon(neighbor, blockAccess, i, j, k, blockOrientation.textureFaceOrig) == icon;
  374. case CONNECT_BY_MATERIAL:
  375. return block.blockMaterial == neighbor.blockMaterial;
  376. default:
  377. return false;
  378. }
  379. }
  380. final boolean exclude(Block block, int face, int metadataMask) {
  381. if (block == null) {
  382. return true;
  383. } else if ((faces & (1 << face)) == 0) {
  384. return true;
  385. } else if (matchMetadata != META_MASK && (matchMetadata & metadataMask) == 0) {
  386. return true;
  387. }
  388. return false;
  389. }
  390. @Override
  391. public final Icon getTileWorld(BlockOrientation blockOrientation, Icon origIcon) {
  392. if (icons == null) {
  393. error("no images loaded, disabling");
  394. return null;
  395. }
  396. IBlockAccess blockAccess = blockOrientation.blockAccess;
  397. Block block = blockOrientation.block;
  398. int i = blockOrientation.i;
  399. int j = blockOrientation.j;
  400. int k = blockOrientation.k;
  401. if (blockOrientation.blockFace < 0 && requiresFace()) {
  402. warn("method=%s is not supported for non-standard block %s:%d @ %d %d %d",
  403. getMethod(), BlockAPI.getBlockName(block), BlockAPI.getMetadataAt(blockAccess, i, j, k), i, j, k
  404. );
  405. return null;
  406. }
  407. if (block == null || RenderPassAPI.instance.skipThisRenderPass(block, renderPass)) {
  408. return null;
  409. }
  410. Integer metadataEntry = matchBlocks.get(block);
  411. matchMetadata = metadataEntry == null ? META_MASK : metadataEntry;
  412. if (exclude(block, blockOrientation.textureFace, blockOrientation.metadataBits)) {
  413. return null;
  414. }
  415. if (height != null && !height.get(j)) {
  416. return null;
  417. }
  418. if (biomes != null && !biomes.get(BiomeAPI.getBiomeIDAt(blockAccess, i, j, k))) {
  419. return null;
  420. }
  421. return getTileWorld_Impl(blockOrientation, origIcon);
  422. }
  423. @Override
  424. public final Icon getTileHeld(BlockOrientation blockOrientation, Icon origIcon) {
  425. if (icons == null) {
  426. error("no images loaded, disabling");
  427. return null;
  428. }
  429. Block block = blockOrientation.block;
  430. if (block == null || RenderPassAPI.instance.skipThisRenderPass(block, renderPass)) {
  431. return null;
  432. }
  433. int face = blockOrientation.textureFace;
  434. if (face < 0 && requiresFace()) {
  435. warn("method=%s is not supported for non-standard block %s:%d",
  436. getMethod(), BlockAPI.getBlockName(block), blockOrientation.metadata
  437. );
  438. return null;
  439. }
  440. if (height != null || biomes != null) {
  441. return null;
  442. }
  443. Integer metadataEntry = matchBlocks.get(block);
  444. matchMetadata = metadataEntry == null ? defaultMetaMask : metadataEntry;
  445. if (exclude(block, face, blockOrientation.metadataBits)) {
  446. return null;
  447. } else {
  448. return getTileHeld_Impl(blockOrientation, origIcon);
  449. }
  450. }
  451. abstract String getMethod();
  452. abstract Icon getTileWorld_Impl(BlockOrientation blockOrientation, Icon origIcon);
  453. abstract Icon getTileHeld_Impl(BlockOrientation blockOrientation, Icon origIcon);
  454. }