LevelData.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. package me.hammerle.supersnuvi.gamelogic;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.util.HashMap;
  7. import java.util.Map.Entry;
  8. public class LevelData
  9. {
  10. private final static int STRING_ID = 1;
  11. private final static int INTEGER_ID = 2;
  12. // container for all custom data
  13. private final HashMap<String, Object> data;
  14. // layers up to bIndex (including) are considered background
  15. // the next layer is the entity spawn layer
  16. // every layer after that is foreground
  17. private int bIndex;
  18. private int width;
  19. private int height;
  20. private int layers;
  21. // storage for tiles
  22. // [layer][width][height]
  23. private int[][][] tiles;
  24. // the file of the level for saving and loading
  25. private final File file;
  26. public LevelData(File file)
  27. {
  28. this.file = file;
  29. this.data = new HashMap<>();
  30. this.bIndex = 0;
  31. this.width = 0;
  32. this.height = 0;
  33. this.layers = 0;
  34. this.tiles = null;
  35. }
  36. public LevelData(File file, int bIndex, int layer, int width, int height)
  37. {
  38. this.file = file;
  39. this.data = new HashMap<>();
  40. this.bIndex = bIndex;
  41. this.width = width;
  42. this.height = height;
  43. this.layers = layer;
  44. this.tiles = new int[layer][width][height];
  45. }
  46. // -------------------------------------------------------------------------
  47. // file writing / reading
  48. // -------------------------------------------------------------------------
  49. private void writeString(FileOutputStream out, String s, boolean identifier) throws IOException
  50. {
  51. // writing type identifier
  52. if(identifier)
  53. {
  54. out.write(STRING_ID);
  55. }
  56. // writing length of string
  57. byte[] b = s.getBytes();
  58. writeInt(out, b.length, false);
  59. // writing the bytes of the string
  60. out.write(b);
  61. }
  62. private String readString(FileInputStream in) throws IOException
  63. {
  64. int length = readInt(in);
  65. byte[] b = new byte[length];
  66. in.read(b);
  67. return new String(b);
  68. }
  69. private void writeInt(FileOutputStream out, int i, boolean identifier) throws IOException
  70. {
  71. // writing type identifier
  72. if(identifier)
  73. {
  74. out.write(INTEGER_ID);
  75. }
  76. // writing the int per byte
  77. out.write(i & 0xFF);
  78. out.write((i >> 8) & 0xFF);
  79. out.write((i >> 16) & 0xFF);
  80. out.write((i >> 24) & 0xFF);
  81. }
  82. private int readInt(FileInputStream in) throws IOException
  83. {
  84. int i = 0;
  85. i |= in.read();
  86. i |= in.read() << 8;
  87. i |= in.read() << 16;
  88. i |= in.read() << 24;
  89. return i;
  90. }
  91. public boolean save()
  92. {
  93. try
  94. {
  95. try(FileOutputStream out = new FileOutputStream(file))
  96. {
  97. // writing number of data fields
  98. writeInt(out, data.size(), false);
  99. // writing keys and data, data varies, key are always strings
  100. for(Entry<String, Object> e : data.entrySet())
  101. {
  102. writeString(out, e.getKey(), false);
  103. if(e.getValue() instanceof Integer)
  104. {
  105. writeInt(out, (Integer) e.getValue(), true);
  106. }
  107. else
  108. {
  109. writeString(out, e.getValue().toString(), true);
  110. }
  111. }
  112. // write background index
  113. writeInt(out, bIndex, false);
  114. // write number of layers
  115. writeInt(out, layers, false);
  116. // write layer width
  117. writeInt(out, width, false);
  118. // write layer height
  119. writeInt(out, height, false);
  120. // write tiles
  121. for(int x = 0; x < layers; x++)
  122. {
  123. for(int y = 0; y < width; y++)
  124. {
  125. for(int z = 0; z < height; z++)
  126. {
  127. writeInt(out, tiles[x][y][z], false);
  128. }
  129. }
  130. }
  131. out.flush();
  132. out.close();
  133. }
  134. return true;
  135. }
  136. catch(IOException ex)
  137. {
  138. ex.printStackTrace();
  139. return false;
  140. }
  141. }
  142. public boolean load()
  143. {
  144. try
  145. {
  146. try (FileInputStream in = new FileInputStream(file))
  147. {
  148. // getting the number of data fields
  149. int fields = readInt(in);
  150. // getting keys and data, data varies, key are always strings
  151. for(; fields > 0; fields--)
  152. {
  153. String key = readString(in);
  154. int id = in.read();
  155. switch(id)
  156. {
  157. case STRING_ID:
  158. data.put(key, readString(in));
  159. break;
  160. case INTEGER_ID:
  161. data.put(key, readInt(in));
  162. break;
  163. default:
  164. System.err.println("fucked up level data");
  165. return false;
  166. }
  167. }
  168. //data.forEach((k, v) -> System.out.println(k + " " + v + " " + v.getClass()));
  169. // getting background index
  170. bIndex = readInt(in);
  171. // getting number of layers
  172. layers = readInt(in);
  173. // getting layer width
  174. width = readInt(in);
  175. // getting layer height
  176. height = readInt(in);
  177. //System.out.println(layers + " " + width + " " + height);
  178. // init tiles
  179. tiles = new int[layers][width][height];
  180. // getting tiles
  181. for(int x = 0; x < layers; x++)
  182. {
  183. for(int y = 0; y < width; y++)
  184. {
  185. for(int z = 0; z < height; z++)
  186. {
  187. tiles[x][y][z] = readInt(in);
  188. }
  189. }
  190. }
  191. in.close();
  192. }
  193. return true;
  194. }
  195. catch(IOException ex)
  196. {
  197. ex.printStackTrace();
  198. return false;
  199. }
  200. }
  201. // -------------------------------------------------------------------------
  202. // variable level data
  203. // -------------------------------------------------------------------------
  204. public void setData(String name, int value)
  205. {
  206. data.put(name, value);
  207. }
  208. public void setData(String name, String value)
  209. {
  210. data.put(name, value);
  211. }
  212. public int getInt(String name, int error)
  213. {
  214. Object o = data.get(name);
  215. if(o == null || !(o instanceof Integer))
  216. {
  217. return error;
  218. }
  219. return (Integer) o;
  220. }
  221. public String getString(String name, String error)
  222. {
  223. Object o = data.get(name);
  224. if(o == null || !(o instanceof String))
  225. {
  226. return error;
  227. }
  228. return (String) o;
  229. }
  230. // -------------------------------------------------------------------------
  231. // level data getter / setter
  232. // -------------------------------------------------------------------------
  233. public int getBackgroundIndex()
  234. {
  235. return bIndex;
  236. }
  237. public void setBackgroundIndex(int bIndex)
  238. {
  239. this.bIndex = bIndex;
  240. }
  241. public int getLayers()
  242. {
  243. return layers;
  244. }
  245. public int getWidth()
  246. {
  247. return width;
  248. }
  249. public int getHeight()
  250. {
  251. return height;
  252. }
  253. // -------------------------------------------------------------------------
  254. // layer stuff
  255. // -------------------------------------------------------------------------
  256. public void clearLayer(int index)
  257. {
  258. if(index >= 0 && index < layers)
  259. {
  260. for(int x = 0; x < width; x++)
  261. {
  262. for(int y = 0; y < height; y++)
  263. {
  264. tiles[index][x][y] = -1;
  265. }
  266. }
  267. }
  268. }
  269. public void copyLayer(int fromIndex, int toIndex)
  270. {
  271. if(fromIndex >= 0 && fromIndex < layers && toIndex >= 0 && toIndex < layers)
  272. {
  273. for(int x = 0; x < width; x++)
  274. {
  275. System.arraycopy(tiles[fromIndex][x], 0, tiles[toIndex][x], 0, height);
  276. }
  277. }
  278. }
  279. public void addLayer()
  280. {
  281. int[][][] newLayers = new int[layers + 1][][];
  282. System.arraycopy(tiles, 0, newLayers, 0, layers);
  283. newLayers[layers] = new int[width][height];
  284. for(int x = 0; x < width; x++)
  285. {
  286. for(int y = 0; y < height; y++)
  287. {
  288. newLayers[layers][x][y] = -1;
  289. }
  290. }
  291. layers++;
  292. tiles = newLayers;
  293. }
  294. public void addLayer(int index)
  295. {
  296. if(index >= layers)
  297. {
  298. addLayer();
  299. return;
  300. }
  301. int[][][] newLayers = new int[layers + 1][][];
  302. System.arraycopy(tiles, 0, newLayers, 0, index);
  303. newLayers[index] = new int[width][height];
  304. for(int x = 0; x < width; x++)
  305. {
  306. for(int y = 0; y < height; y++)
  307. {
  308. newLayers[index][x][y] = -1;
  309. }
  310. }
  311. System.arraycopy(tiles, index, newLayers, index + 1, layers - index);
  312. layers++;
  313. tiles = newLayers;
  314. }
  315. public void removeLayer(int index)
  316. {
  317. if(layers <= 1)
  318. {
  319. layers = 0;
  320. tiles = new int[0][0][0];
  321. return;
  322. }
  323. int[][][] newLayers = new int[layers - 1][][];
  324. if(index > 0)
  325. {
  326. System.arraycopy(tiles, 0, newLayers, 0, index);
  327. }
  328. int left = layers - index - 1;
  329. if(left > 0)
  330. {
  331. System.arraycopy(tiles, index + 1, newLayers, index, left);
  332. }
  333. layers--;
  334. tiles = newLayers;
  335. }
  336. public void setLayerSize(int w, int h)
  337. {
  338. int[][][] newLayers = new int[layers][w][h];
  339. int cw = Math.min(w, width);
  340. int ch = Math.min(h, height);
  341. for(int l = 0; l < layers; l++)
  342. {
  343. for(int x = 0; x < cw; x++)
  344. {
  345. System.arraycopy(tiles[l][x], 0, newLayers[l][x], 0, ch);
  346. }
  347. }
  348. width = w;
  349. height = h;
  350. tiles = newLayers;
  351. }
  352. // -------------------------------------------------------------------------
  353. // tile getter / setter
  354. // -------------------------------------------------------------------------
  355. public int getInteractionTile(int x, int y)
  356. {
  357. if(x < 0 || y < 0 || x >= width || y >= height || bIndex >= layers)
  358. {
  359. return -1;
  360. }
  361. return tiles[bIndex][x][y];
  362. }
  363. public int getTile(int layer, int x, int y)
  364. {
  365. return tiles[layer][x][y];
  366. }
  367. public void setTile(int layer, int x, int y, int value)
  368. {
  369. tiles[layer][x][y] = value;
  370. }
  371. // -------------------------------------------------------------------------
  372. // entity layer
  373. // -------------------------------------------------------------------------
  374. public void deactivateEntity(int x, int y)
  375. {
  376. tiles[bIndex + 1][x][y] = -Math.abs(tiles[bIndex + 1][x][y]);
  377. }
  378. public void activateEntities()
  379. {
  380. int[][] ent = tiles[bIndex + 1];
  381. forEachEntity((x, y, tile) ->
  382. {
  383. if(tile < 0)
  384. {
  385. ent[x][y] = Math.abs(ent[x][y]);
  386. }
  387. }, 0, width, 0, height);
  388. }
  389. // -------------------------------------------------------------------------
  390. // tile iterators
  391. // -------------------------------------------------------------------------
  392. public void forEachBackground(TileConsumer c, int sx, int ex, int sy, int ey)
  393. {
  394. int max = Math.min(layers - 1, bIndex);
  395. sx = Math.max(0, sx);
  396. sy = Math.max(0, sy);
  397. ex = Math.min(width, ex);
  398. ey = Math.min(height, ey);
  399. for(int l = 0; l <= max; l++)
  400. {
  401. for(int x = sx; x < ex; x++)
  402. {
  403. for(int y = sy; y < ey; y++)
  404. {
  405. c.consume(x, y, tiles[l][x][y]);
  406. }
  407. }
  408. }
  409. }
  410. public void forEachInteractTile(TileConsumer c)
  411. {
  412. if(bIndex < layers)
  413. {
  414. for(int y = 0; y < width; y++)
  415. {
  416. for(int z = 0; z < height; z++)
  417. {
  418. c.consume(y, z, tiles[bIndex][y][z]);
  419. }
  420. }
  421. }
  422. }
  423. public void forEachEntity(TileConsumer c, int sx, int ex, int sy, int ey)
  424. {
  425. int l = bIndex + 1;
  426. if(l < layers)
  427. {
  428. sx = Math.max(0, sx);
  429. sy = Math.max(0, sy);
  430. ex = Math.min(width, ex);
  431. ey = Math.min(height, ey);
  432. int[][] ent = tiles[l];
  433. for(int x = sx; x < ex; x++)
  434. {
  435. for(int y = sy; y < ey; y++)
  436. {
  437. c.consume(x, y, ent[x][y]);
  438. }
  439. }
  440. }
  441. }
  442. public void forEachForeground(TileConsumer c, int sx, int ex, int sy, int ey)
  443. {
  444. sx = Math.max(0, sx);
  445. sy = Math.max(0, sy);
  446. ex = Math.min(width, ex);
  447. ey = Math.min(height, ey);
  448. for(int l = bIndex + 2; l < layers; l++)
  449. {
  450. for(int x = sx; x < ex; x++)
  451. {
  452. for(int y = sy; y < ey; y++)
  453. {
  454. c.consume(x, y, tiles[l][x][y]);
  455. }
  456. }
  457. }
  458. }
  459. }