/* * 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.inventory; import java.lang.reflect.Field; import java.util.HashSet; import java.util.Set; import gnu.trove.iterator.TIntByteIterator; import gnu.trove.iterator.TIntIntIterator; import gnu.trove.iterator.TLongFloatIterator; import gnu.trove.iterator.TLongObjectIterator; import gnu.trove.map.hash.TIntByteHashMap; import gnu.trove.map.hash.TIntIntHashMap; import net.minecraft.server.v1_6_R3.Block; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.getspout.spout.block.mcblock.WrappedMCBlock; import org.getspout.spout.player.SpoutCraftPlayer; import org.getspout.spoutapi.SpoutManager; import org.getspout.spoutapi.inventory.MaterialManager; import org.getspout.spoutapi.material.CustomBlock; import org.getspout.spoutapi.material.Material; import org.getspout.spoutapi.material.MaterialData; import org.getspout.spoutapi.packet.PacketBlockData; import org.getspout.spoutapi.packet.PacketItemName; import org.getspout.spoutapi.packet.SpoutPacket; import org.getspout.spoutapi.player.SpoutPlayer; import org.getspout.spoutapi.util.map.TIntPairFloatHashMap; import org.getspout.spoutapi.util.map.TIntPairHashSet; import org.getspout.spoutapi.util.map.TIntPairObjectHashMap; public abstract class AbstractBlockManager implements MaterialManager { protected final TIntPairObjectHashMap<String> customNames = new TIntPairObjectHashMap<String>(100); protected final TIntPairFloatHashMap originalHardness = new TIntPairFloatHashMap(); protected final TIntPairFloatHashMap originalFriction = new TIntPairFloatHashMap(); protected final TIntByteHashMap originalOpacity = new TIntByteHashMap(); protected final TIntIntHashMap originalLight = new TIntIntHashMap(); protected Set<org.getspout.spoutapi.material.Block> cachedBlockData = null; @Override public void reset() { customNames.clear(); for (Player player : Bukkit.getServer().getOnlinePlayers()) { if (player instanceof SpoutCraftPlayer) { if (((SpoutPlayer) player).isSpoutCraftEnabled()) { ((SpoutPlayer) player).sendPacket(new PacketItemName(0, (short) 0, "[resetall]")); } } } } public void onPlayerJoin(SpoutPlayer player) { if ((player).isSpoutCraftEnabled()) { for (TLongObjectIterator<String> it = customNames.iterator(); it.hasNext();) { it.advance(); (player).sendPacket(new PacketItemName(TIntPairHashSet.longToKey1(it.key()), (short) TIntPairHashSet.longToKey2(it.key()), it.value())); } } } @Override public void setItemName(Material item, String name) { customNames.put(item.getRawId(), item.getRawData(), name); for (Player player : Bukkit.getServer().getOnlinePlayers()) { if (player instanceof SpoutCraftPlayer) { if (((SpoutPlayer) player).isSpoutCraftEnabled()) { ((SpoutPlayer) player).sendPacket(new PacketItemName(item.getRawId(), (short) item.getRawData(), name)); } } } } @Override public void resetName(Material item) { int id = item.getRawId(); int data = item.getRawData(); if (customNames.containsKey(id, data)) { customNames.remove(id, data); for (Player player : Bukkit.getServer().getOnlinePlayers()) { if (player instanceof SpoutCraftPlayer) { if (((SpoutPlayer) player).isSpoutCraftEnabled()) { ((SpoutPlayer) player).sendPacket(new PacketItemName(id, (short) data, "[reset]")); } } } } } @Override public String getStepSound(org.getspout.spoutapi.material.Block block) { // TODO Auto-generated method stub return null; } @Override public void setStepSound(org.getspout.spoutapi.material.Block block, String url) { // TODO Auto-generated method stub } @Override public void resetStepSound(org.getspout.spoutapi.material.Block block) { // TODO Auto-generated method stub } @Override public float getFriction(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } return Block.byId[id].frictionFactor; } @Override public void setFriction(org.getspout.spoutapi.material.Block block, float friction) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (!originalFriction.containsKey(id, data)) { originalFriction.put(id, data, getFriction(block)); } Block.byId[id].frictionFactor = friction; updateBlockAttributes(id, (short) data); // invalidate cache } @Override public void resetFriction(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (originalFriction.containsKey(id, data)) { setFriction(block, originalFriction.get(id, data)); originalFriction.remove(id, data); } updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public float getHardness(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } // Access the protected strength field in Block Block mBlock = Block.byId[id]; float hardness = 999999999f; // Probably useless safeguard try { Field field = Block.class.getDeclaredField("strength"); field.setAccessible(true); hardness = field.getFloat(mBlock); } catch (Exception e) { e.printStackTrace(); } return hardness; } @Override public void setHardness(org.getspout.spoutapi.material.Block block, float hardness) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (!originalHardness.containsKey(id, data)) { originalHardness.put(id, data, getHardness(block)); } Block b = Block.byId[id]; if (b instanceof WrappedMCBlock) { ((WrappedMCBlock) b).setHardness(hardness); } updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public void resetHardness(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (originalHardness.containsKey(id, data)) { setHardness(block, originalHardness.get(id, data)); originalHardness.remove(id, data); } updateBlockAttributes(id, (short) data); // invalidate cache } @Override public boolean isOpaque(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); return Block.t[id]; } @Override public void setOpaque(org.getspout.spoutapi.material.Block block, boolean opacity) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (!originalOpacity.containsKey(id)) { originalOpacity.put(id, (byte) (isOpaque(block) ? 1 : 0)); } Block.t[id] = opacity; updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public void resetOpacity(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (originalOpacity.containsKey(id)) { setOpaque(block, originalOpacity.get(id) != 0); originalOpacity.remove(id); } updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public int getLightLevel(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } return Block.lightEmission[id]; } @Override public void setLightLevel(org.getspout.spoutapi.material.Block block, int level) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (!originalLight.containsKey(id)) { originalLight.put(id, getLightLevel(block)); } Block.lightEmission[id] = level; updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public void resetLightLevel(org.getspout.spoutapi.material.Block block) { int id = block.getRawId(); if (block instanceof CustomBlock) { id = ((CustomBlock) block).getBlockId(); } int data = block.getRawData(); if (originalLight.containsKey(id)) { setLightLevel(block, originalLight.get(id)); originalLight.remove(id); } updateBlockAttributes(id, (short) data); // Invalidate cache } @Override public Set<org.getspout.spoutapi.material.Block> getModifiedBlocks() { // Hit cache first if (cachedBlockData != null) { return cachedBlockData; } Set<org.getspout.spoutapi.material.Block> modified = new HashSet<org.getspout.spoutapi.material.Block>(); TLongFloatIterator i = originalFriction.iterator(); while (i.hasNext()) { i.advance(); int id = TIntPairHashSet.longToKey1(i.key()); int data = TIntPairHashSet.longToKey2(i.key()); org.getspout.spoutapi.material.Block block = MaterialData.getBlock(id, (short) data); if (block != null) { modified.add(block); } } i = originalHardness.iterator(); while (i.hasNext()) { i.advance(); int id = TIntPairHashSet.longToKey1(i.key()); int data = TIntPairHashSet.longToKey2(i.key()); org.getspout.spoutapi.material.Block block = MaterialData.getBlock(id, (short) data); if (block != null) { modified.add(block); } } TIntIntIterator j = originalLight.iterator(); while (j.hasNext()) { j.advance(); org.getspout.spoutapi.material.Block block = MaterialData.getBlock(j.key()); if (block != null) { modified.add(block); } } TIntByteIterator k = originalOpacity.iterator(); while (k.hasNext()) { k.advance(); org.getspout.spoutapi.material.Block block = MaterialData.getBlock(k.key()); if (block != null) { modified.add(block); } } cachedBlockData = modified; // Save to cache return modified; } private void updateBlockAttributes(int id, short data) { org.getspout.spoutapi.material.Block block = MaterialData.getBlock(id, data); if (block != null) { cachedBlockData = null; HashSet<org.getspout.spoutapi.material.Block> toUpdate = new HashSet<org.getspout.spoutapi.material.Block>(1); toUpdate.add(block); SpoutPacket updatePacket = new PacketBlockData(toUpdate); for (SpoutPlayer player : SpoutManager.getOnlinePlayers()) { if (player.isSpoutCraftEnabled()) { player.sendPacket(updatePacket); } } } } }