Package org.getspout.spout.block

Source Code of org.getspout.spout.block.SpoutCraftChunk

/*
* This file is part of SpoutcraftPlugin.
*
* Copyright (c) 2011 SpoutcraftDev <http://spoutcraft.org//>
* SpoutcraftPlugin is licensed under the GNU Lesser General Public License.
*
* SpoutcraftPlugin 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.
*
* SpoutcraftPlugin 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.getspout.spout.block;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

import gnu.trove.map.hash.TIntIntHashMap;

import net.minecraft.server.v1_6_R3.Chunk;
import net.minecraft.server.v1_6_R3.ChunkProviderServer;
import net.minecraft.server.v1_6_R3.WorldServer;

import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_6_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_6_R3.CraftWorld;

import org.getspout.spoutapi.Spout;
import org.getspout.spoutapi.SpoutManager;
import org.getspout.spoutapi.SpoutWorld;
import org.getspout.spoutapi.block.SpoutChunk;
import org.getspout.spoutapi.material.CustomBlock;
import org.getspout.spoutapi.material.MaterialData;

public class SpoutCraftChunk extends CraftChunk implements SpoutChunk {
  protected final ConcurrentHashMap<Integer, Integer> queuedId = new ConcurrentHashMap<Integer, Integer>();
  protected final ConcurrentHashMap<Integer, Byte> queuedData = new ConcurrentHashMap<Integer, Byte>();
    //TODO Very experimental...may need to be reverted
  protected static final Set<SpoutCraftChunk> queuedChunks = new ConcurrentSkipListSet<SpoutCraftChunk>();
    //protected static final Set<SpoutCraftChunk> queuedChunks = Collections.newSetFromMap(new ConcurrentHashMap<SpoutCraftChunk, Boolean>());

  public final TIntIntHashMap powerOverrides = new TIntIntHashMap();

  transient private final int worldHeight;
  transient private final int worldHeightMinusOne;
  transient private final int xBitShifts;
  transient private final int zBitShifts;

  public SpoutCraftChunk(Chunk chunk) {
    super(chunk);

    SpoutWorld world = Spout.getServer().getWorld(getWorld().getUID());

    this.worldHeight = world != null ? world.getMaxHeight() : 256;
    this.xBitShifts = world != null ? world.getXBitShifts() : 12;
    this.zBitShifts = world != null ? world.getZBitShifts() : 8;
    worldHeightMinusOne = worldHeight - 1;
  }

  @Override
  public Block getBlock(int x, int y, int z) {
    return new SpoutCraftBlock(this, (getX() << 4) | (x & 0xF), y & worldHeightMinusOne, (getZ() << 4) | (z & 0xF));
  }

  private Block getBlockFromPos(int pos) {
    int x = (pos >> xBitShifts) & 0xF;
    int y = (pos) & worldHeightMinusOne;
    int z = (pos >> zBitShifts) & 0xF;

    return getBlock(x, y, z);

  }

  public void onTick() {
        //Apply queued ids on blocks
        final Iterator<Entry<Integer, Integer>> i = queuedId.entrySet().iterator();
        while (i.hasNext()) {
            final Entry<Integer, Integer> entry = i.next();
            Block block = getBlockFromPos(entry.getKey());
            block.setTypeId(entry.getValue());
            i.remove();
        }
        //Apply queued data on blocks
        if (queuedId.isEmpty()) {
            final Iterator<Entry<Integer, Byte>> j = queuedData.entrySet().iterator();
            while (j.hasNext()) {
                //If another thread adds to the id queue, we need to halt and let the next tick apply it
                //TODO Even possible, needed? Doesn't add much overhead to check this...
                if (!queuedId.isEmpty()) {
                    break;
                }
                final Entry<Integer, Byte> entry = j.next();
                final Block block = getBlockFromPos(entry.getKey());
                block.setData(entry.getValue());
                j.remove();
            }
        }
  }

  protected void onReset() {
    // TODO finalize queuing
  }

  public static void updateTicks() {
    Iterator<SpoutCraftChunk> i = SpoutCraftChunk.queuedChunks.iterator();
    while (i.hasNext()) {
      SpoutCraftChunk chunk = i.next();
      chunk.onTick();
      i.remove();
    }
  }

  public static void replaceAllBukkitChunks() {
    replaceAllBukkitChunks(false);
  }

  public static void resetAllBukkitChunks() {
    replaceAllBukkitChunks(true);
  }

  private static void replaceAllBukkitChunks(boolean reset) {
    List<World> worlds = Bukkit.getServer().getWorlds();
    for (World world : worlds) {
      try {
        CraftWorld cw = (CraftWorld) world;
        Field worldServer = CraftWorld.class.getDeclaredField("world");
        worldServer.setAccessible(true);
        ChunkProviderServer cps = ((WorldServer) worldServer.get(cw)).chunkProviderServer;
        for (Chunk c : cps.chunks.values()) {
                    if (reset) {
            if (c.bukkitChunk instanceof SpoutCraftChunk) {
              ((SpoutCraftChunk) c.bukkitChunk).onReset();
            }
            resetBukkitChunk(c.bukkitChunk);
          } else {
            replaceBukkitChunk(c.bukkitChunk);
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public static SpoutCraftChunk getChunkSafe(org.bukkit.Chunk chunk) {
    if (chunk == null) {
      return null;
    }
    if (replaceBukkitChunk(chunk)) {
      return (SpoutCraftChunk) ((CraftChunk)chunk).getHandle().bukkitChunk;
    }
    return (SpoutCraftChunk) chunk;
  }

  public static boolean replaceBukkitChunk(org.bukkit.Chunk chunk) {
    CraftChunk handle = (CraftChunk) ((CraftChunk) chunk).getHandle().bukkitChunk;
    if (handle != null) {
      boolean replace = false;
      if (handle.getX() != chunk.getX()) {
        replace = true;
      }
      if (handle.getZ() != chunk.getZ()) {
        replace = true;
      }
      if (handle.getClass().hashCode() != SpoutCraftChunk.class.hashCode()) {
        replace = true;
      }
      org.bukkit.Chunk loopbackChunk = ((CraftChunk)chunk).getHandle().bukkitChunk;
      if (loopbackChunk != chunk) {
        replace = true;
      }
      if (replace) {
        ((CraftChunk) chunk).getHandle().bukkitChunk = new SpoutCraftChunk(((CraftChunk) chunk).getHandle());
      }
      return true;
    }
    return false;
  }

  public static void resetBukkitChunk(org.bukkit.Chunk chunk) {
    ((CraftChunk) chunk).getHandle().bukkitChunk = new CraftChunk(((CraftChunk) chunk).getHandle());
  }

  @Override
  public Serializable setData(String id, Serializable data) {
    return SpoutManager.getChunkDataManager().setChunkData(id, getWorld(), getX(), getZ(), data);
  }

  @Override
  public Serializable getData(String id) {
    return SpoutManager.getChunkDataManager().getChunkData(id, getWorld(), getX(), getZ());
  }

  @Override
  public Serializable removeData(String id) {
    return SpoutManager.getChunkDataManager().removeChunkData(id, getWorld(), getX(), getZ());
  }

  @Override
  public short[] getCustomBlockIds() {
    return SpoutManager.getChunkDataManager().getCustomBlockIds(getWorld(), getX(), getZ());
  }

  @Override
  public void setCustomBlockIds(short[] ids) {
    SpoutManager.getChunkDataManager().setCustomBlockIds(getWorld(), getX(), getZ(), ids);
  }

  @Override
  public short getCustomBlockId(int x, int y, int z) {
    short[] ids = getCustomBlockIds();
    if (ids == null) {
      return 0;
    }
    int index = ((x & 0xF) << xBitShifts) | ((z & 0xF) << zBitShifts) | (y & worldHeightMinusOne);
    return ids[index];
  }

  @Override
  public short setCustomBlockId(int x, int y, int z, short id) {
    short[] ids = getCustomBlockIds();
    if (ids == null) {
      ids = new short[16*16*worldHeight];
      setCustomBlockIds(ids);
    }
    int index = ((x & 0xF) << xBitShifts) | ((z & 0xF) << zBitShifts) | (y & worldHeightMinusOne);
    short old = ids[index];
    ids[index] = id;
    return old;
  }

  @Override
  public CustomBlock setCustomBlock(int x, int y, int z, CustomBlock block) {
    if (block == null) {
      throw new NullPointerException("Custom Block can not be null!");
    }
    short old = setCustomBlockId(x, y, z, (short) block.getCustomId());
    return MaterialData.getCustomBlock(old);
  }

  @Override
  public byte[] getCustomBlockData() {
    return SpoutManager.getChunkDataManager().getCustomBlockData(getWorld(), getX(), getZ());
  }

  @Override
  public void setCustomBlockData(byte[] data) {
    SpoutManager.getChunkDataManager().setCustomBlockData(getWorld(), getX(), getZ(), data);
  }

  @Override
  public byte getCustomBlockData(int x, int y, int z) {
    byte[] data = getCustomBlockData();
    if (data == null) {
      return 0;
    }
    int index = ((x & 0xF) << xBitShifts) | ((z & 0xF) << zBitShifts) | (y & worldHeightMinusOne);
    return data[index];
  }

  @Override
  public byte setCustomBlockData(int x, int y, int z, byte data) {
    byte[] dats = getCustomBlockData();
    if (dats == null) {
      dats = new byte[16*16*worldHeight];
      setCustomBlockData(dats);
    }
    int index = ((x & 0xF) << xBitShifts) | ((z & 0xF) << zBitShifts) | (y & worldHeightMinusOne);
    byte old = dats[index];
    dats[index] = data;
    return old;
  }

  @Override
  public CustomBlock setCustomBlock(int x, int y, int z, CustomBlock block, byte data) {
    if (block == null) {
      throw new NullPointerException("Custom Block can not be null!");
    }
    short old = setCustomBlockId(x, y, z, (short) block.getCustomId());
    setCustomBlockData(x, y, z, data);
    return MaterialData.getCustomBlock(old);
  }
}
TOP

Related Classes of org.getspout.spout.block.SpoutCraftChunk

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.