Package org.spoutcraft.client.gui.minimap

Source Code of org.spoutcraft.client.gui.minimap.MapCalculator

/*
* This file is part of Spoutcraft.
*
* Copyright (c) 2011 SpoutcraftDev <http://spoutcraft.org/>
* Spoutcraft is licensed under the GNU Lesser General Public License.
*
* Spoutcraft is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Spoutcraft is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.spoutcraft.client.gui.minimap;

import java.util.Random;

import net.minecraft.src.Minecraft;
import net.minecraft.src.AxisAlignedBB;
import net.minecraft.src.Chunk;
import net.minecraft.src.EntityLiving;
import net.minecraft.src.Material;
import net.minecraft.src.World;

import org.spoutcraft.api.Spoutcraft;
import org.spoutcraft.client.SpoutClient;
import org.spoutcraft.client.chunkcache.HeightMap;

public class MapCalculator implements Runnable {
  /**
   * Multiply two colors by each other. Treats 0xff as 1.0.
   *
   * Yourself came up with the algorithm, I'm sure it makes sense to someone
   *
   * @param x
   *    Color to multiply
   * @param y
   *    Other color to multiply
   * @return multiplied color
   */
  public int colorMult(int x, int y) {
    int res = 0;
    for (int octet = 0; octet < 3; ++octet) {
      res |= (((x & 0xff) * (y & 0xff)) / 0xff) << (octet << 3);
      x >>= 8;
      y >>= 8;
    }
    return res;
  }

  private final float distance(int x1, int y1, int x2, int y2) {
    return (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
  }

  private final boolean blockIsSolid(Chunk chunk, int x, int y, int z) {
    if (y > 255)
      return false;
    if (y < 0)
      return true;
    try {
      int id = chunk.getBlockID(x, y, z);
      int meta = chunk.getBlockMetadata(x, y, z);
      return BlockColor.getBlockColor(id, meta).alpha > 0;
    } catch (Exception e) {
      return false;
    }
  }

  private final int getBlockHeight(World world, int x, int z) {
    if (MinimapConfig.getInstance().isCavemap()) {
      Chunk chunk = world.getChunkFromBlockCoords(x, z);
      cmdist.setSeed((x & 0xffff) | ((z & 0xffff) << 16));
      float dist = distance((int) Minecraft.getMinecraft().thePlayer.posX, (int) Minecraft.getMinecraft().thePlayer.posZ, x, z);
      int y = (int) Minecraft.getMinecraft().thePlayer.posY;
      if (dist > 5)
        y -= (cmdist.nextInt((int) (dist)) - ((int) dist / 2));
      x &= 0xf;
      z &= 0xf;

      if (y < 0) {
        y = 0;
      } else if (y > 255) {
        y = 255;
      }

      if (blockIsSolid(chunk, x, y, z)) {
        int itery = y;
        while (true) {
          itery++;
          if (itery > y + 10)
            return y + 10;
          if (!blockIsSolid(chunk, x, itery, z)) {
            return itery - 1;
          }
        }
      }
      while (y > -1) {
        y--;
        if (blockIsSolid(chunk, x, y, z)) {
          return y;
        }
      }
      return -1;
    }

    return world.getHeightValue(x, z) - 1;

    // return world.b(x, z).b(x & 0xf, z & 0xf);
    /*
     * li chunk = world.b(x, z); int y = (int)(game.h.aM); // starty; x &=
     * 0xf; z &= 0xf;
     *
     * //while (y > 0) // {
     *
     *
     * if (getBlockColor(id, meta).alpha == 0) return -1; // y--; else return
     * y + 1; // what //}
     */
    // return -1;
  }

  private int getBlockColor(World world, int x, int y, int z) {
    int color24 = 0;

    try {
      if (MinimapConfig.getInstance().isColor() && !MinimapConfig.getInstance().isCavemap()) {
        if (x == (int) map.getPlayerX() && z == (int) map.getPlayerZ())
          return 0xff0000;
        if ((world.getBlockMaterial(x, y + 1, z) == Material.ice) || (world.getBlockMaterial(x, y + 1, z) == Material.snow)) {
          color24 = 0xffffff;
        } else {
          BlockColor col = BlockColor.getBlockColor(world.getBlockId(x, y, z), world.getBlockMetadata(x, y, z));
          color24 = col.color;
        }
      }
    } catch (Exception e) {
      return 0;
    }

    return color24;
  }

  private int getBlockHeightMap(World world, int x, int y, int z) {
    int height = y - 128;
    double sc = Math.log10(Math.abs(height) / 8.0D + 1.0D) / 1.3D;
    int result = 0x80;

    if (height >= 0) {
      result = (int) (sc * (0xff - result)) + result;
    } else {
      height = Math.abs(height);
      result = result - (int) (sc * result);
    }
    return result;
  }

  private int getBlockLight(World world, int x, int y, int z) {
    int light = world.getBlockLightValue_do(x, y + 1, z, false) * 17;
    int min = 32;
    if (light < min) {
      light = min;
    }
    if (MinimapConfig.getInstance().isLightmap()) {
      light *= 1.3f;
    } else if (MinimapConfig.getInstance().isCavemap()) {
      light *= 0.5;
      light += 64;
    }

    if (light > 255) {
      light = 255;
    } else if (light < 0) {
      light = 0;
    }

    return light;
  }

  private void mapCalc() {
    if (Minecraft.getMinecraft().thePlayer == null || Minecraft.getMinecraft().theWorld == null)
      return;
    try {
      final boolean square = MinimapConfig.getInstance().isSquare();
      final World data = Minecraft.getMinecraft().theWorld;
      int renderSize;
      int startX;
      int startZ;
      synchronized (map) {
        if (map.zoom != MinimapConfig.getInstance().getZoom()) {
          map.zoom = MinimapConfig.getInstance().getZoom();
          switch (map.zoom) {
            case 0:
              map.renderSize = Map.ZOOM_0;
              break;
            case 1:
              map.renderSize = Map.ZOOM_1;
              break;
            case 2:
              map.renderSize = Map.ZOOM_2;
              break;
            default:
              map.renderSize = Map.ZOOM_2;
              break;
          }
          map.renderOff = map.renderSize / 2;
          map.clear();
        }
        map.square = square;

        map.update(Minecraft.getMinecraft().thePlayer.posX, Minecraft.getMinecraft().thePlayer.posZ);
        renderSize = map.renderSize;
        startX = (int) (map.getPlayerX() - map.renderOff);
        startZ = (int) (map.getPlayerZ() - map.renderOff);
      }

      for (int worldX = startX; worldX < startX + renderSize; worldX++) {
        for (int worldZ = startZ; worldZ < startZ + renderSize; worldZ++) {
          int worldY = getBlockHeight(data, worldX, worldZ);

          int pixelX = worldX - startX;
          if (pixelX >= renderSize) {
            pixelX -= renderSize;
          }

          int pixelZ = worldZ - startZ;
          pixelZ = renderSize - pixelZ;
          if (pixelZ >= renderSize) {
            pixelZ -= renderSize;
          }

          if (square || MinimapUtils.insideCircle(startX + renderSize / 2, startZ + renderSize / 2, renderSize / 2, worldX, worldZ)) {
            int color = getBlockColor(data, worldX, worldY, worldZ);
            if (color == 0) {
              map.clearColorPixel(pixelX, pixelZ);
            } else {
              map.setColorPixel(pixelX, pixelZ, color);
            }

            short height = (short) data.getHeightValue(worldX, worldZ);
            short reference = (short) data.getHeightValue(worldX + 1, worldZ + 1);
            map.heightimg.setARGB(pixelZ, pixelX, getHeightColor(height, reference));
            map.setLightPixel(pixelX, pixelZ, getBlockLight(data, worldX, worldY, worldZ));

          } else {
            map.clearColorPixel(pixelX, pixelZ);
            map.heightimg.setARGB(pixelX, pixelZ, 0);
            map.setLightPixel(pixelX, pixelZ, 255);
          }
        }
      }

      synchronized (map) {
        for (Waypoint pt : MinimapConfig.getInstance().getWaypoints(MinimapUtils.getWorldName())) {
          if (pt.enabled) {
            boolean render = false;
            if (square) {
              render = Math.abs(map.getPlayerX() - pt.x) < map.renderSize && Math.abs(map.getPlayerZ() - pt.z) < map.renderSize;
            } else {
              render = MinimapUtils.insideCircle(startX + map.renderSize / 2, startZ + map.renderSize / 2, map.renderSize / 2, pt.x, pt.z);
            }
            if (pt.deathpoint && !MinimapConfig.getInstance().isDeathpoints()) {
              render = false;
            }
            if (render) {
              int pixelX = pt.x - startX;

              int pixelZ = pt.z - startZ;
              pixelZ = map.renderSize - pixelZ;

              int scale = map.zoom + 2;
              if (map.zoom > 2) {
                scale += 2;
              }
              if (map.zoom > 1) {
                scale += 1;
              }

              int color = 0xEE2C2C;
              if (pt == MinimapConfig.getInstance().getFocussedWaypoint()) {
                color = 0xff00ffff;
              }
              drawCircle(pixelX, pixelZ, scale + map.zoom + 1, pt.deathpoint ? color : 0);
              drawCircle(pixelX, pixelZ, scale, pt.deathpoint ? 0 : color);
            }
          }
        }
        for (Waypoint pt : MinimapConfig.getInstance().getServerWaypoints()) {
          boolean render = false;
          if (square) {
            render = Math.abs(map.getPlayerX() - pt.x) < map.renderSize && Math.abs(map.getPlayerZ() - pt.z) < map.renderSize;
          } else {
            render = MinimapUtils.insideCircle(startX + map.renderSize / 2, startZ + map.renderSize / 2, map.renderSize / 2, pt.x, pt.z);
          }
          if (render) {
            int pixelX = pt.x - startX;

            int pixelZ = pt.z - startZ;
            pixelZ = map.renderSize - pixelZ;

            int scale = map.zoom + 2;
            if (map.zoom > 2) {
              scale += 2;
            }
            if (map.zoom > 1) {
              scale += 1;
            }

            int color = 0x3366CC;
            if (pt == MinimapConfig.getInstance().getFocussedWaypoint()) {
              color = 0xff00ffff;
            }
            drawCircle(pixelX, pixelZ, scale + map.zoom + 1, 0);
            drawCircle(pixelX, pixelZ, scale, color);
          }
        }
      }
    } catch (Throwable whatever) {  }
  }

  private void drawCircle(int x, int y, int radius, int color) {
    try {
      for (int dx = -radius; dx <= radius; dx++) {
        for (int dy = -radius; dy <= radius; dy++) {
          if (x + dx < map.renderSize && x + dx > 0 && y + dy < map.renderSize && y + dy > 0) {
            if (MinimapUtils.insideCircle(x, y, radius, x + dx, y + dy)) {
              map.setColorPixel(x + dx, y + dy, color);
            }
          }
        }
      }
    } catch (ArrayIndexOutOfBoundsException ignore) {
    } // happens with fast movement
  }

  /**
   * Check if a render is necessary, and if so, do one.
   */
  private void tryARender() {
    if (Minecraft.getMinecraft().thePlayer == null || Minecraft.getMinecraft().theWorld == null)
      return;
    try {
      double x = Minecraft.getMinecraft().thePlayer.posX;
      double z = Minecraft.getMinecraft().thePlayer.posZ;
      if (MinimapConfig.getInstance().isEnabled() && map.isDirty(x, z)) {
//        long start = System.currentTimeMillis();
        if (MinimapConfig.getInstance().getScanRadius() > 0) {
          int radius = MinimapConfig.getInstance().getScanRadius() << 4;
          for (int cx = (int) (x - radius); cx <= (int) (x + radius); cx += 16) {
            for (int cz = (int) (z - radius); cz <= (int) (z + radius); cz += 16) {
              Chunk chunk = Minecraft.getMinecraft().theWorld.getChunkFromBlockCoords((int) cx, (int) cz);
              org.spoutcraft.client.chunkcache.HeightMapAgent.scanChunk(chunk);
            }
          }
        }
        //long dur = System.currentTimeMillis() - start;
        //int chunks = (int) Math.pow(MinimapConfig.getInstance().getScanRadius() * 2, 2);
        //System.out.println("Took " + dur + "ms to scan " + chunks + " chunks.\nThat is " + (float) (dur/(float)chunks) + " per chunk!");
        mapCalc();

        entityCalc();
        map.timer = 1;
      }
    } catch (RuntimeException e) {
      throw e;
    } finally {
      map.timer++;
    }
  }

  private void entityCalc() {
    synchronized(map.watchedEntities) {
      map.watchedEntities.clear();
      if (!Spoutcraft.hasPermission("spout.plugin.minimap.showentities")) {
        return;
      }
      if (!MinimapConfig.getInstance().isShowingEntities()) {
        return;
      }
      int radius = map.renderSize / 2;
      double playerX = map.getPlayerX();
      double playerZ = map.getPlayerZ();
      for (Object ob:SpoutClient.getHandle().theWorld.getEntitiesWithinAABB(EntityLiving.class, AxisAlignedBB.getBoundingBox(playerX - radius, 0, playerZ - radius, playerX + radius, 256, playerZ + radius))) {
        net.minecraft.src.Entity e = (net.minecraft.src.Entity) ob;
        if (!MinimapConfig.getInstance().isEntityVisible(e.getClass())) {
          continue;
        }
        WatchedEntity w = new WatchedEntity(e);
        if (w.getTexture() != null) {
          map.watchedEntities.add(w);
        }
      }
    }
  }

  /**
   * the run() to implement runnable - the main function of the other thread.
   * this simply idles and the actual work is done in onRenderTick().
   */
  public void run() {
  }

  /**
   * Called each tick of the render.
   */
  void onRenderTick() {
    if (Minecraft.getMinecraft() != null && Minecraft.getMinecraft().theWorld != null) {
      tryARender();
    }
  }

  /**
   * Random used to distort cave map
   */
  public Random cmdist = new Random();

  private Map map;

  /**
   * This constructor inits state, but does not start the thread.
   *
   * @param minimap
   *      Minimap instance to initialize off
   */
  public MapCalculator(ZanMinimap minimap) {
    map = minimap.map;
  }

  /**
   * Start up the other thread. The thread may return early at this point, as
   * there might not be a Minecraft instance available yet. if that occurs,
   * the thread will be restarted by the keep-alive in onRenderTick().
   */
  public void start() {
  }

  public static int getHeightColor(short height, short reference) {
    int hdiff = height - reference;
    int color = 0x00000000;
    if (hdiff != 0 && reference != -1) {
      boolean ascending = hdiff < 0;
      hdiff *= 2;
      hdiff += 256;
      if (hdiff > 255) {
        hdiff = 255;
      }
      if (hdiff < 0) {
        hdiff = 0;
      }
      if (!ascending) {
        hdiff = 255 - hdiff;
      }
      color = 0x55000000 | ((hdiff << 16) + (hdiff << 8) + hdiff);
    }
    return color;
  }

  public static int getHeightColor(int x, int z, HeightMap heightMap) {
    short height = heightMap.getHeight(x, z);
    short reference = heightMap.getHeight(x + 1, z + 1);

    return getHeightColor(height, reference);
  }
}
TOP

Related Classes of org.spoutcraft.client.gui.minimap.MapCalculator

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.