Package Hexel.blocks

Source Code of Hexel.blocks.BlockSimulator

package Hexel.blocks;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import Hexel.Engine;
import Hexel.LogData;
import Hexel.Resources;
import Hexel.blocks.types.Block;
import Hexel.blocks.types.BlockDirt;
import Hexel.blocks.types.BlockEmpty;
import Hexel.blocks.types.BlockLeaf;
import Hexel.blocks.types.BlockSeed;
import Hexel.blocks.types.BlockTransparent;
import Hexel.blocks.types.BlockWater;
import Hexel.blocks.types.BlockWood;
import Hexel.chunk.Chunk;
import Hexel.chunk.ChunkVisibilityManager;
import Hexel.chunk.Chunks;
import Hexel.chunk.HighestBlockChunk;
import Hexel.math.Vector2i;
import Hexel.math.Vector3i;
import Hexel.util.Container;
import Hexel.util.Pair;

public class BlockSimulator {

  private Chunks chunks;

  private Engine engine;

  private ChunkVisibilityManager cVisMan;

  private BlockRules blockRules;

  public static final int DONT_RUN = Integer.MAX_VALUE;

  private Vector3i tmp3i = new Vector3i();
  private Vector2i tmp2i = new Vector2i();

  private ArrayList<Vector3i> toUpdate = new ArrayList<Vector3i>();
  private HashSet<Chunk> fastified = new HashSet<Chunk>();

  public BlockSimulator(Engine engine, Chunks chunks, ChunkVisibilityManager cVisMan) {
    this.chunks = chunks;
    this.cVisMan = cVisMan;
    this.engine = engine;
    this.blockRules = new BlockRules(engine, new PointInSimRange() {
      @Override
      public boolean pointIsInRange(Vector3i v) {
        for (int i = 0; i < toUpdate.size(); i++){
          Vector3i c = toUpdate.get(i);
          if (c.x*32 <= v.x && c.x*32+32 > v.x &&
              c.y*16 <= v.y && c.y*16+16 > v.y &&
              c.z*32 <= v.z && c.z*32+32 > v.z){
            return true;
          }
        }
        return false;
      }
    });
  }

  private ExecutorService ste = Executors.newSingleThreadExecutor();
  public void step() {
    this.ste.execute(new Runnable() {
      @Override
      public void run() {
        sim();
      }
    });

  }

  public static int nSim = 0;
  public static long timeX = 0;
  public static long timeY = 0;
  public static long timeZ = 0;

  private Hashtable<Vector3i, BlockDelta> deltas = new Hashtable<Vector3i, BlockDelta>();

  private void sim(){

    int step = engine.time;
    toUpdate.clear();
    fastified.clear();
    boolean goAgain = false;

    Set<Vector3i> loadedChunks = this.cVisMan.simulatedChunks;
    int minNextSimStep = Integer.MAX_VALUE;
    for (Vector3i pos : loadedChunks) {
      toUpdate.add(pos);
      Chunk chunk = BlockSimulator.this.chunks.getChunk(pos);
      minNextSimStep = Math.min(minNextSimStep, chunk.nextSimStep);
    }
    if (minNextSimStep == Integer.MAX_VALUE)
      LogData.set("minNextSim", Integer.MAX_VALUE);
    else
      LogData.set("minNextSim", (minNextSimStep - engine.time) + " " + minNextSimStep);

    do {
      deltas.clear();
      goAgain = false;
      for (Vector3i pos : toUpdate) {
        Chunk chunk = BlockSimulator.this.chunks.getChunk(pos);
        chunk.beingUpdated = true;
        simChunk(pos, deltas, step);
        if (chunk.nextSimStep == -1){
          goAgain = true;
        }
      }
      for (BlockDelta delta : deltas.values()) {
        BlockSimulator.this.chunks.setBlock(delta.x, delta.y, delta.z, delta.block, tmp3i, tmp2i, null);
        BlockSimulator.this.chunks.setStepsToSim(delta.x, delta.y, delta.z, delta.srcStepsToSim-1, tmp3i);
        if (delta.srcStepsToSim-1 > 0){
          tmp3i.x = (int) Math.floor(delta.x / 32.0);
          tmp3i.y = (int) Math.floor(delta.y / 16.0);
          tmp3i.z = (int) Math.floor(delta.z / 32.0);
          Chunk chunk = BlockSimulator.this.chunks.getChunk(tmp3i);
          if (!fastified.contains(chunk)){
            chunk.fastMode = true;
            fastified.add(chunk);
          }
        }
        delta.recycle();
      }
    } while (goAgain);

    for (Vector3i pos : toUpdate) {
      Chunk chunk = BlockSimulator.this.chunks.getChunk(pos);
      chunk.needFirstSim = false;
      chunk.beingUpdated = false;
    }
    for (Chunk chunk : fastified){
      chunk.fastMode = false;
    }
  }

  private void simChunk(Vector3i p, Hashtable<Vector3i, BlockDelta> deltas, int step){
    Chunk chunk = this.chunks.getChunk(p);

    if (chunk.nextSimStep != -1 && chunk.nextSimStep > step) {
      return;
    }
    chunk.nextSimStep = Integer.MAX_VALUE;

    Vector2i tmp2 = new Vector2i();

    for (int x = 0; x < 32; x++) {
      for (int y = 0; y < 16; y++) {
        for (int z = 0; z < 32; z++) {
          Block b = chunk.get(x, y, z);
          int gx = p.x * 32 + x;
          int gy = p.y * 16 + y;
          int gz = p.z * 32 + z;
          HighestBlockChunk hbc = chunks.getHighestBlockChunkAtXY(gx, gy, tmp2);
          simBlock(gx, gy, gz, chunk, hbc, b, step, deltas);
          int lx = gx - chunk.cx*32;
          int ly = gy - chunk.cy*16;
          int lz = gz - chunk.cz*32;
          chunk.nextSimStep = Math.min(chunk.nextSimSteps[lx][ly][lz], chunk.nextSimStep);
        }
      }
    }
  }

  public interface BlockDeltaAdder {
    public abstract void addBlockDelta(BlockDelta delta);
    public abstract boolean hasBlockDelta(Vector3i v);
    public abstract BlockDelta getBlockDelta(Vector3i v);
  }

  public interface PointInSimRange {
    public abstract boolean pointIsInRange(Vector3i v);
  }

  private void simBlock(int bx, int by, int bz, Chunk c, HighestBlockChunk hbc, Block b, int step, final Hashtable<Vector3i, BlockDelta> deltas){
    int lx = bx - c.cx*32;
    int ly = by - c.cy*16;
    int lz = bz - c.cz*32;
    boolean fastMode = c.stepsToSim[lx][ly][lz] > 0;
    if (!fastMode){
      int nextSimStep = c.nextSimSteps[lx][ly][lz];
      if (nextSimStep != -1 && nextSimStep > step){
        return;
      }
    }
    tmp3i.x = bx;
    tmp3i.y = by;
    tmp3i.z = bz;
    if (deltas.containsKey(tmp3i))
      return;
    c.nextSimSteps[lx][ly][lz] = Integer.MAX_VALUE;
    ArrayList<BlockRule> rules = getRules(b);

    final Container<Boolean> hadMatch = new Container<Boolean>();
    hadMatch.contents = false;

    for (BlockRule rule : rules) {
      int nextSimStep = rule.run(bx, by, bz, fastMode, b, c, hbc, this.chunks, step, new BlockDeltaAdder(){
        @Override
        public void addBlockDelta(BlockDelta delta){
          Vector3i pos = new Vector3i();
          pos.x = delta.x;
          pos.y = delta.y;
          pos.z = delta.z;
          if (hasBlockDelta(pos)){
            try {
              throw new Exception("multiple deltas per block");
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
          deltas.put(pos, delta);
          hadMatch.contents = true;
        }
        @Override
        public boolean hasBlockDelta(Vector3i v){
          return deltas.containsKey(v);
        }

        @Override
        public BlockDelta getBlockDelta(Vector3i v){
          return deltas.get(v);
        }
      });
      c.nextSimSteps[lx][ly][lz] = Math.min(c.nextSimSteps[lx][ly][lz], nextSimStep);
      if (hadMatch.contents){
        break;
      }
    }
    if (rules.size() == 0 || !hadMatch.contents){
      c.stepsToSim[lx][ly][lz] = 0;
    }
    else if (c.stepsToSim[lx][ly][lz] > 0){
      c.stepsToSim[lx][ly][lz] -= 1;
      if (c.stepsToSim[lx][ly][lz] > 0){
        c.nextSimSteps[lx][ly][lz] = -1;
      }
    }
  }

  private ArrayList<BlockRule> getRules(Block b){
    ArrayList<BlockRule> rules = null;
    if (b instanceof BlockSeed) {
      rules = blockRules.seedRules;
    }
    else if (b instanceof BlockWood) {
      rules = blockRules.woodRules;
    }
    else if (b instanceof BlockWater) {
      rules = blockRules.waterRules;
    }
    else if (b instanceof BlockLeaf) {
      rules = blockRules.leafRules;
    }
    else if (b instanceof BlockDirt) {
      rules = blockRules.dirtRules;
    }
    else if (b instanceof BlockEmpty) {
      rules = blockRules.emptyRules;
    }
    else if (b instanceof BlockTransparent) {
      rules = blockRules.transparentRules;
    }
    else {
      rules = blockRules.everywhereRules;
    }
    return rules;
  }
}
TOP

Related Classes of Hexel.blocks.BlockSimulator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.