Package world

Source Code of world.MapManager$MapsendThread

package world;

import java.util.HashMap;
import java.util.HashSet;

import datatypes.XZasDouble;

import packets.SPacket;
import packets.s2cpackets.S0x32;
import packets.s2cpackets.S0x33;
import entities.Player;
import exceptions.MCConnectionException;
import tools.ArrayMerge;
import worldmap.MapColumn;
import worldmap.MapColumnChunk;
import worldmap.WorldMap;


/**
* The mapmanager will keep track of the state of the map.
*
* It monitors players and send players new map-parts if they need them.
* It send map updates to players when they need them.
* It will request clients to unload map-parts if they should do that.
*
*/
public final class MapManager extends WorldStateMonitor {

  private WorldMap worldmap = new WorldMap();
  private HashMap<Player, HashSet<Long>> playerLoadedColumns = new HashMap<Player, HashSet<Long>>();
 
 
  public MapManager(WorldState state) {
    super(state);
  }
 
 
 

 
 
  private void setPlayerHasLoadedColumn(Player player, int x, int z) {
    long coordinate = XZasDouble.toLong(x, z);
   
    if(!playerLoadedColumns.containsKey(player)) {
      playerLoadedColumns.put(player, new HashSet<Long>());
    }
    playerLoadedColumns.get(player).add(coordinate);
  }
 
  private void unsetPlayerHasLoadedColumn(Player player, int x, int z) {
    long coordinate = XZasDouble.toLong(x, z);
   
    try {
      playerLoadedColumns.get(player).remove(coordinate);
    } catch(Exception e) { } //nothing to do on catch
  }
 
  private boolean playerHasLoadedColumn(Player player, int x, int z) {
    long coordinate = XZasDouble.toLong(x, z);
   
    try {
      return   playerLoadedColumns.get(player).contains(coordinate);
    } catch(Exception e) { } //nothing to do on catch
    return false ;
  }
 
 
 
 
 
  /**
   * Sends the initial area of 7x7 columns to the player.
   * This is always send before spawing or re-spawning.
   *
   * @param player
   * @throws MCConnectionException
   */
  public void sendInitialMap(Player player) throws MCConnectionException {
    //first send needed init-chunks
    // in order to calculate the correct column, divide the location by 16
    int px = (int) player.getLocation().x / 16;
    int pz = (int) player.getLocation().z / 16;

   
    for(int x = px-3; x <= px+3; x++) {
      for(int z = pz-3; z <= pz+3; z++) {
        sendInitColumn(x, z, player);
      }
    }
   
    for(int x = px-3; x <= px+3; x++) {
      for(int z = pz-3; z <= pz+3; z++) {
        sendColumn(x, z, player);
      }
    }
    System.out.println("ALL DONE");
    //start a thread which will start sending new mapchunks when needed.
    //new Thread(new MapsendThread(player)).start();
  }

 
  /**
   * Requests the client to initialize a new column. Note that this should
   * sent before the column data itself.
   *
   * @param x
   * @param z
   * @param player
   * @throws MCConnectionException
   */
  private void sendInitColumn(int x, int z, Player player) throws MCConnectionException {
    SPacket p = new S0x32(x, z, true);
    state.connectionManager().sendPacketTo(player, p);
    setPlayerHasLoadedColumn(player, x, z);
  }
 
 
 

 
 
 
  /**
   * Send all nececairy data to the so it can build up the column for the given
   * coordinates.
   *
   * @param x
   * @param z
   * @param player
   * @throws MCConnectionException
   */
  private void sendColumn(int x, int z, Player player) throws MCConnectionException {
    MapColumn column = worldmap.getColumn(x, z);
   
    short maskerbit = 1;
   
    //sending 16 chunks from bottom up to top
    short bitmask = 0;
    short bitmaskaddarray = 0;
   
    byte[] block_ids= null;
    byte[] block_metadata = null;
    byte[] block_light = null;
    byte[] block_skylight= null;

    //TODO
    byte[] biome_addarray  = new byte[16*16];
    for(int i = 0; i<biome_addarray.length; i++) {
      biome_addarray[i] = 0x09;
    }
   
   
    //TODO?
    byte[] block_addarray  = new byte[0];
   
   
    for(byte y = 0; y < 16; y++) {
      if(!column.isAir(y)) {
        bitmask |= maskerbit;
        MapColumnChunk chunk = column.getChunk(y);
        if(block_ids == null) {
          block_ids = chunk.getBlocksIds();
          block_metadata = chunk.getBlocksMetadata();
          block_light = chunk.getBlocksLight();
          block_skylight = chunk.getBlocksSkylight();
        } else {
          block_ids = ArrayMerge.mergeBytes(block_ids, chunk.getBlocksIds());
          block_metadata = ArrayMerge.mergeBytes(block_metadata, chunk.getBlocksMetadata());
          block_light = ArrayMerge.mergeBytes(block_light, chunk.getBlocksLight());
          block_skylight = ArrayMerge.mergeBytes(block_skylight, chunk.getBlocksSkylight());
        }
       
      }
      maskerbit <<= maskerbit;
    }
   
    byte[] r = ArrayMerge.mergeBytes(block_ids, block_metadata);
    r = ArrayMerge.mergeBytes(r, block_light);
    r = ArrayMerge.mergeBytes(r, block_skylight);
    r = ArrayMerge.mergeBytes(r, block_addarray);
    r = ArrayMerge.mergeBytes(r, biome_addarray);   
   
 
    SPacket p = new S0x33(x, z, true, bitmask, bitmaskaddarray, r);
    System.out.println("L: "+r.length);
    state.connectionManager().sendPacketTo(player, p);
   
  }
 
 
  class AllSentException extends Exception {
    private static final long serialVersionUID = 1085415294421705987L;
  }
 
 
  /**
   * Thread wich will ping a client for a undefined amount of time.
   * Thread stops automagically and silently when a connection is
   * closed or an error occurs.
   */
  class MapsendThread implements Runnable {

    private Player player;
   
    public MapsendThread(Player player) {
      this.player = player;
    }
   
    private void sendColumn(int x, int z) {
      try {
        MapManager.this.sendInitColumn(x, z, player);
        MapManager.this.sendColumn(x, z, player);
      } catch (MCConnectionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return;
      }
    }
   
    @Override
    public void run() {
      System.out.println("Starting the mapsendthread.");
      while(true) {
        try {
          sendNextColumn();
        } catch (AllSentException e) {
          try {
            Thread.sleep(100);
          } catch (InterruptedException e1) {
            e1.printStackTrace();
          }
        }
      }
    }
   
   
    /**
     * Decide which column has to be sent to the client.
     * Then send it.
     * @throws AllSentException
     */
    private void sendNextColumn() throws AllSentException {
      int cx = (int) (player.getLocation().x / 16);
      int cz = (int) (player.getLocation().z / 16);
     
      //fill a radius_max grid around the player with columns
      int radius_max = 15;
      for(int radius = 0; radius < radius_max; radius++) {
        int z_upper = cz + radius;
        int z_lower = cz - radius;
       
        for(int x = cx - radius; x < cx + radius; x++) {
          if(!playerHasLoadedColumn(player, x, z_upper)) {
            sendColumn(x, z_upper);
            return;
          }
         
          if(!playerHasLoadedColumn(player, x, z_lower)) {
            sendColumn(x, z_lower);   
            return;
          }
        }
       
        int x_upper = cx + radius;
        int x_lower = cx - radius;
        for(int z = cz - radius; z < cz + radius; z++) {
          if(!playerHasLoadedColumn(player, x_lower, z)) {
            sendColumn(x_lower, z);
            return;
          }
         
          if(!playerHasLoadedColumn(player, x_upper, z)) {
            sendColumn(x_upper, z);   
            return;
          }
         
        }
      }
     
      throw new AllSentException();
     
    }
   
  }

}
TOP

Related Classes of world.MapManager$MapsendThread

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.