PageRenderTime 41ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

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

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