DEADSOFTWARE

Rewrite fluid updater
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameFluidsThread.java
1 package ru.deadsoftware.cavedroid.game;
3 import java.util.Arrays;
5 import static ru.deadsoftware.cavedroid.GameScreen.GP;
6 import static ru.deadsoftware.cavedroid.game.GameItems.*;
8 public class GameFluidsThread extends Thread {
10 private static final int FLUID_UPDATE_INTERVAL_MS = 150;
11 private static final int FLUID_STATES = 5;
13 private static final int[] WATER_IDS = {8, 60, 61, 62, 63};
14 private static final int[] LAVA_IDS = {9, 64, 65, 65, 67};
16 private long fluidLastUpdateTimestamp = 0;
18 private int getBlockState(int id) {
19 return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id);
20 }
22 private int getNextBlockState(int id) {
23 if (!isFluid(id)) {
24 return -1;
25 }
26 int state = getBlockState(id);
27 if (state < FLUID_STATES - 1) {
28 return state + 1;
29 }
30 return -1;
31 }
33 private int getNextBlockStateId(int id) {
34 int nextState = getNextBlockState(id);
35 if (nextState == -1) return 0;
36 if (isWater(id)) {
37 return WATER_IDS[nextState];
38 }
39 return LAVA_IDS[nextState];
40 }
42 private int id(int x, int y) {
43 return GP.world.getForeMap(x, y);
44 }
46 private boolean sameFluid(int thisId, int thatId) {
47 return isFluid(thatId) && isWater(thatId) == isWater(thisId);
48 }
50 private boolean noFluidNearby(int x, int y) {
51 return !isFluid(id(x, y - 1)) &&
52 (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) &&
53 (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y));
54 }
56 private boolean drainFluid(int x, int y) {
57 if (getBlockState(id(x, y)) > 0) {
58 if (noFluidNearby(x, y)) {
59 GP.world.setForeMap(x, y, getNextBlockStateId(id(x, y)));
60 }
61 if (!isFluid(id(x, y))) {
62 GP.world.setForeMap(x, y, 0);
63 return true;
64 }
65 }
66 return false;
67 }
69 private void flowFluidTo(int thisId, int x, int y, int nextStateId) {
70 int thatId = id(x, y);
71 if (fluidCanFlowThere(thisId, thatId)) {
72 GP.world.setForeMap(x, y, nextStateId);
73 } else if (isWater(thisId) && isLava(thatId)) {
74 if (getBlockState(thatId) > 0) {
75 GP.world.setForeMap(x, y, 4); //cobblestone
76 } else {
77 GP.world.setForeMap(x, y, 68); //obsidian
78 }
79 } else if (isLava(thisId) && isWater(thatId)) {
80 GP.world.setForeMap(x, y, 1); //stone
81 }
82 }
84 private void flowFluid(int x, int y) {
85 int id = id(x, y);
86 if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) {
87 int nextState = getNextBlockState(id);
88 int nextStateId = getNextBlockStateId(id);
89 if (nextState == 1) {
90 nextStateId++;
91 }
92 flowFluidTo(id, x - 1, y, nextStateId);
93 flowFluidTo(id, x + 1, y, nextStateId);
94 } else {
95 flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]);
96 }
98 }
100 private void updateFluids(int x, int y) {
101 if (!isFluid(id(x, y))) return;
102 if (drainFluid(x, y)) return;
103 flowFluid(x, y);
106 private void fluidUpdater() {
107 int midScreen = (int) (GP.renderer.getCamX() + GP.renderer.getWidth() / 2) / 16;
108 for (int y = 0; y < GP.world.getHeight(); y++) {
109 for (int x = 0; x < (int) (GP.renderer.getWidth() / 2) / 16 + 1; x++) {
110 updateFluids(midScreen + x, y);
111 updateFluids(midScreen - x, y);
116 @Override
117 public void run() {
118 while (!this.isInterrupted()) {
119 if (System.currentTimeMillis() - fluidLastUpdateTimestamp > FLUID_UPDATE_INTERVAL_MS) {
120 fluidUpdater();
121 fluidLastUpdateTimestamp = System.currentTimeMillis();