DEADSOFTWARE

Store block references intead of ids
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / world / GameWorldFluidsLogicControllerTask.java
index d996cf42989c41a1025b54fb1c1fd2b77e053cf0..ed6b1ec634d70cc880ddb81f9d28897eaf811f16 100644 (file)
 package ru.deadsoftware.cavedroid.game.world;
 
 import com.badlogic.gdx.utils.Timer;
+import ru.deadsoftware.cavedroid.game.GameItemsHolder;
 import ru.deadsoftware.cavedroid.game.GameScope;
 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
+import ru.deadsoftware.cavedroid.game.model.block.Block;
 
+import javax.annotation.CheckForNull;
 import javax.inject.Inject;
-import java.util.Arrays;
-
-import static ru.deadsoftware.cavedroid.game.GameItems.*;
+import java.util.*;
 
 @GameScope
 public class GameWorldFluidsLogicControllerTask extends Timer.Task {
 
     public static final float FLUID_UPDATE_INTERVAL_SEC = 0.1f;
-    private static final int FLUID_STATES = 5;
-
-    private static final int[] WATER_IDS = {8, 60, 61, 62, 63};
-    private static final int[] LAVA_IDS = {9, 64, 65, 66, 67};
 
     private final GameWorld mGameWorld;
     private final MobsController mMobsController;
+    private final GameItemsHolder mGameItemsHolder;
+
+    private final Map<Class<? extends Block.Fluid>, List<? extends Block.Fluid>> mFluidStatesMap;
 
     @Inject
     GameWorldFluidsLogicControllerTask(GameWorld gameWorld,
-                                       MobsController mobsController) {
+                                       MobsController mobsController,
+                                       GameItemsHolder gameItemsHolder) {
         mGameWorld = gameWorld;
         mMobsController = mobsController;
+        mGameItemsHolder = gameItemsHolder;
+
+        final List<Block.Water> waters = mGameItemsHolder.getBlocksByType(Block.Water.class);
+        waters.sort(Comparator.comparingInt(Block.Water::getState));
+
+        final List<Block.Lava> lavas = mGameItemsHolder.getBlocksByType(Block.Lava.class);
+        lavas.sort(Comparator.comparingInt(Block.Lava::getState));
+
+        mFluidStatesMap = new HashMap<>();
+        mFluidStatesMap.put(Block.Water.class, waters);
+        mFluidStatesMap.put(Block.Lava.class, lavas);
     }
 
-    private int getBlockState(int id) {
-        return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id);
+    @CheckForNull
+    private List<? extends Block.Fluid> getFluidStateList(Block.Fluid fluid) {
+        return mFluidStatesMap.get(fluid.getClass());
     }
 
-    private int getNextBlockState(int id) {
-        if (!isFluid(id)) {
+    private int getCurrentStateIndex(Block.Fluid fluid) {
+        @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
+
+        if (stateList == null) {
             return -1;
         }
-        int state = getBlockState(id);
-        if (state < FLUID_STATES - 1) {
-            return state + 1;
-        }
-        return -1;
+
+        return stateList.indexOf(fluid);
     }
 
-    private int getNextBlockStateId(int id) {
-        int nextState = getNextBlockState(id);
-        if (nextState == -1) {
-            return 0;
+    @CheckForNull
+    private Block.Fluid getNextStateBlock(Block.Fluid fluid) {
+        @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
+
+        if (stateList == null) {
+            return null;
         }
-        if (isWater(id)) {
-            return WATER_IDS[nextState];
+
+        int currentState = stateList.indexOf(fluid);
+
+        if (currentState < 0) {
+            return null;
         }
-        return LAVA_IDS[nextState];
-    }
 
-    private int id(int x, int y) {
-        return mGameWorld.getForeMap(x, y);
-    }
+        int nextState = currentState + 1;
+
+        if (nextState == 1) {
+            nextState++;
+        }
 
-    private boolean sameFluid(int thisId, int thatId) {
-        return isFluid(thatId) && isWater(thatId) == isWater(thisId);
+        if (nextState < stateList.size()) {
+            return stateList.get(nextState);
+        }
+
+        return null;
     }
 
     private boolean noFluidNearby(int x, int y) {
-        return !isFluid(id(x, y - 1)) &&
-                (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) &&
-                (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y));
+        return !mGameWorld.getForeMap(x, y - 1).isFluid() &&
+                (!mGameWorld.getForeMap(x - 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x - 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()) &&
+                (!mGameWorld.getForeMap(x + 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x + 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState());
     }
 
     private boolean drainFluid(int x, int y) {
-        if (getBlockState(id(x, y)) > 0) {
+        final Block block = mGameWorld.getForeMap(x, y);
+
+        if (!(block instanceof Block.Fluid fluid)) {
+            return true;
+        }
+
+        if (fluid.getState() > 0) {
             if (noFluidNearby(x, y)) {
-                mGameWorld.setForeMap(x, y, getNextBlockStateId(id(x, y)));
-            }
-            if (!isFluid(id(x, y))) {
-                mGameWorld.setForeMap(x, y, 0);
-                return true;
+                @CheckForNull final Block nextState = getNextStateBlock(fluid);
+                if (nextState == null) {
+                    mGameWorld.resetForeMap(x, y);
+                    return true;
+                }
+
+                mGameWorld.setForeMap(x, y, nextState);
             }
         }
         return false;
     }
 
-    private void flowFluidTo(int thisId, int x, int y, int nextStateId) {
-        int thatId = id(x, y);
-        if (fluidCanFlowThere(thisId, thatId)) {
-            mGameWorld.setForeMap(x, y, nextStateId);
-        } else if (isWater(thisId) && isLava(thatId)) {
-            if (getBlockState(thatId) > 0) {
-                mGameWorld.setForeMap(x, y, 4); //cobblestone
+    private boolean fluidCanFlowThere(Block.Fluid fluid, Block targetBlock) {
+        return targetBlock == mGameItemsHolder.getFallbackBlock() ||
+                (!targetBlock.getParams().getHasCollision() && !targetBlock.isFluid()) ||
+                (fluid.getClass() == targetBlock.getClass() && fluid.getState() < ((Block.Fluid)targetBlock).getState());
+    }
+
+    private void flowFluidTo(Block.Fluid currentFluid, int x, int y, Block.Fluid nextStateFluid) {
+        final Block targetBlock = mGameWorld.getForeMap(x, y);
+
+        if (fluidCanFlowThere(currentFluid, targetBlock)) {
+            mGameWorld.setForeMap(x, y, nextStateFluid);
+        } else if (currentFluid.isWater() && targetBlock.isLava()) {
+            if (((Block.Lava)targetBlock).getState() > 0) {
+                mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("cobblestone"));
             } else {
-                mGameWorld.setForeMap(x, y, 68); //obsidian
+                mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("obsidian"));
             }
-        } else if (isLava(thisId) && isWater(thatId)) {
-            mGameWorld.setForeMap(x, y, 1); //stone
+        } else if (currentFluid.isLava() && targetBlock.isWater()) {
+            mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("stone"));
         }
     }
 
     private void flowFluid(int x, int y) {
-        int id = id(x, y);
-        if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) {
-            int nextState = getNextBlockState(id);
-            int nextStateId = getNextBlockStateId(id);
-            if (nextState == 1) {
-                nextStateId++;
+        Block.Fluid fluid = (Block.Fluid) mGameWorld.getForeMap(x, y);
+        @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
+
+        if (stateList == null) {
+            return;
+        }
+
+        if (fluid.getState() < stateList.size() - 1 && mGameWorld.getForeMap(x, y + 1).hasCollision()) {
+            @CheckForNull Block.Fluid nextState = getNextStateBlock(fluid);
+
+            if (nextState == null) {
+                return;
             }
-            flowFluidTo(id, x - 1, y, nextStateId);
-            flowFluidTo(id, x + 1, y, nextStateId);
+
+            flowFluidTo(fluid, x - 1, y, nextState);
+            flowFluidTo(fluid, x + 1, y, nextState);
         } else {
-            flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]);
+            flowFluidTo(fluid, x, y + 1, stateList.get(1));
         }
 
     }
 
     private void updateFluids(int x, int y) {
-        if (!isFluid(id(x, y))) {
+        if (!mGameWorld.getForeMap(x, y).isFluid()) {
             return;
         }
         if (drainFluid(x, y)) {