Package org.spout.vanilla.material

Source Code of org.spout.vanilla.material.VanillaBlockMaterial

/*
* This file is part of Vanilla.
*
* Copyright (c) 2011 Spout LLC <http://www.spout.org/>
* Vanilla is licensed under the Spout License Version 1.
*
* Vanilla 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.
*
* In addition, 180 days after any changes are published, you can use the
* software, incorporating those changes, under the terms of the MIT license,
* as described in the Spout License Version 1.
*
* Vanilla 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,
* the MIT license and the Spout License Version 1 along with this program.
* If not, see <http://www.gnu.org/licenses/> for the GNU Lesser General Public
* License and see <http://spout.in/licensev1> for the full license, including
* the MIT license.
*/
package org.spout.vanilla.material;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.spout.api.Engine;
import org.spout.api.Platform;
import org.spout.api.Spout;
import org.spout.api.component.block.BlockComponent;
import org.spout.api.entity.Entity;
import org.spout.api.entity.Player;
import org.spout.api.event.Cause;
import org.spout.api.event.entity.EntityInteractBlockEvent;
import org.spout.api.event.player.Action;
import org.spout.api.event.player.PlayerInteractBlockEvent;
import org.spout.api.geo.LoadOption;
import org.spout.api.geo.cuboid.Block;
import org.spout.api.geo.cuboid.Chunk;
import org.spout.api.inventory.ItemStack;
import org.spout.api.material.BlockMaterial;
import org.spout.api.material.block.BlockFace;
import org.spout.api.material.block.BlockFaces;
import org.spout.api.material.range.CuboidEffectRange;
import org.spout.api.material.range.EffectRange;
import org.spout.api.math.IntVector3;
import org.spout.api.render.RenderMaterial;
import org.spout.api.util.flag.Flag;
import org.spout.api.util.flag.FlagBundle;

import org.spout.math.GenericMath;
import org.spout.math.vector.Vector2f;
import org.spout.physics.collision.shape.CollisionShape;
import org.spout.vanilla.VanillaPlugin;
import org.spout.vanilla.component.entity.substance.Item;
import org.spout.vanilla.component.world.sky.Sky;
import org.spout.vanilla.data.Instrument;
import org.spout.vanilla.data.MoveReaction;
import org.spout.vanilla.data.RedstonePowerMode;
import org.spout.vanilla.data.VanillaData;
import org.spout.vanilla.data.VanillaRenderMaterials;
import org.spout.vanilla.data.drops.flag.DropFlags;
import org.spout.vanilla.data.drops.flag.PlayerFlags;
import org.spout.vanilla.data.drops.type.block.BlockDrops;
import org.spout.vanilla.data.effect.SoundEffect;
import org.spout.vanilla.data.effect.store.SoundEffects;
import org.spout.vanilla.data.tool.ToolLevel;
import org.spout.vanilla.data.tool.ToolType;
import org.spout.vanilla.event.material.network.BlockActionEvent;
import org.spout.vanilla.material.block.redstone.IndirectRedstoneSource;
import org.spout.vanilla.material.block.redstone.RedstoneSource;
import org.spout.vanilla.render.VanillaEffects;

public abstract class VanillaBlockMaterial extends BlockMaterial implements VanillaMaterial, IndirectRedstoneSource {
  public static short REDSTONE_POWER_MAX = 15;
  public static short REDSTONE_POWER_MIN = 0;
  private final int minecraftId;
  private float resistance;
  private int meleeDamage = 1;
  private boolean liquidObstacle = true;
  private SoundEffect stepSound = SoundEffects.STEP_STONE;
  private final BlockDrops drops = new BlockDrops();
  private final Set<ToolType> miningTypes = new HashSet<ToolType>();
  private ToolLevel miningLevel = ToolLevel.NONE;
  private final Vector2f pos = null; // TODO: Block item rendering

  public VanillaBlockMaterial(String name, int id, String model, CollisionShape shape, Class<? extends BlockComponent>... components) {
    this((short) 0, name, id, model, shape, components);
    if (getEngine().getPlatform() == Platform.CLIENT) {
      if (!getModel().getRenderMaterial().getRenderEffects().contains(VanillaEffects.SKY_TIME)) {
        getModel().getRenderMaterial().addRenderEffect(VanillaEffects.SKY_TIME);
        getModel().getRenderMaterial().addBufferEffect(VanillaEffects.LIGHTING);
      }
    }
  }

  public VanillaBlockMaterial(short dataMask, String name, int id, String model, CollisionShape shape, Class<? extends BlockComponent>... components) {
    super(dataMask, name, model, shape, components);
    this.minecraftId = id;
    this.setTransparent();
    this.getDrops().SILK_TOUCH.add(this);
    this.getDrops().DEFAULT.add(this);
    this.getDrops().EXPLOSION.add(this);
    if (getEngine().getPlatform() == Platform.CLIENT) {
      if (!getModel().getRenderMaterial().getRenderEffects().contains(VanillaEffects.SKY_TIME)) {
        getModel().getRenderMaterial().addRenderEffect(VanillaEffects.SKY_TIME);
        getModel().getRenderMaterial().addBufferEffect(VanillaEffects.LIGHTING);
      }
    }
  }

  public VanillaBlockMaterial(String name, int id, int data, VanillaBlockMaterial parent, String model, CollisionShape shape, Class<? extends BlockComponent>... components) {
    super(name, data, parent, model, shape, components);
    this.minecraftId = id;
    this.setTransparent();
    this.getDrops().SILK_TOUCH.add(this);
    this.getDrops().DEFAULT.add(this);
    this.getDrops().EXPLOSION.add(this);
    if (getEngine().getPlatform() == Platform.CLIENT) {
      if (!getModel().getRenderMaterial().getRenderEffects().contains(VanillaEffects.SKY_TIME)) {
        getModel().getRenderMaterial().addRenderEffect(VanillaEffects.SKY_TIME);
        getModel().getRenderMaterial().addBufferEffect(VanillaEffects.LIGHTING);
      }
    }
  }

  public final Engine getEngine() {
    return VanillaPlugin.getInstance().getEngine();
  }

  @Override
  public final int getMinecraftId() {
    return minecraftId;
  }

  @Override
  public short getMinecraftData(short data) {
    return (short) (data & 0xF);
  }

  @Override
  public RenderMaterial getRenderMaterial() {
    return VanillaRenderMaterials.BLOCKS_MATERIAL;
  }

  @Override
  public Vector2f getSpritePosition() {
    return pos;
  }

  /**
   * Called when this block is destroyed because of an explosion
   *
   * @param block that got ignition
   * @param cause of the ignition
   */
  public void onIgnite(Block block, Cause<?> cause) {
    HashSet<Flag> dropFlags = new HashSet<Flag>();
    if (GenericMath.getRandom().nextInt(100) < 77) {
      dropFlags.add(DropFlags.NO_DROPS);
    } else {
      dropFlags.add(DropFlags.EXPLOSION_DROPS);
    }
    this.destroy(block, dropFlags, cause);
  }

  @Override
  public void onPostDestroy(Block block, Set<Flag> flags) {
    //TODO stack items together for more performance
    final Random random = GenericMath.getRandom();
    for (ItemStack item : this.getDrops().getDrops(random, flags)) {
      Item.dropNaturally(block.getPosition(), item);
    }
  }

  @Override
  public void onUpdate(BlockMaterial oldMaterial, Block block) {
    super.onUpdate(oldMaterial, block);
  }

  @Override
  public boolean canCreate(Block block, short data, Cause<?> cause) {
    return !block.getMaterial().isPlacementObstacle();
  }

  @Override
  public VanillaBlockMaterial setFriction(float friction) {
    return (VanillaBlockMaterial) super.setFriction(friction);
  }

  @Override
  public VanillaBlockMaterial setRestitution(float restitution) {
    return (VanillaBlockMaterial) super.setRestitution(restitution);
  }

  @Override
  public VanillaBlockMaterial setShape(CollisionShape shape) {
    return (VanillaBlockMaterial) super.setShape(shape);
  }

  @Override
  public VanillaBlockMaterial setHardness(float hardness) {
    return (VanillaBlockMaterial) super.setHardness(hardness);
  }

  /**
   * Sets the sound played when the block is being walked over or is being placed
   *
   * @param sound to play
   * @return this Material
   */
  public VanillaBlockMaterial setStepSound(SoundEffect sound) {
    this.stepSound = sound;
    return this;
  }

  /**
   * Gets the sound played when the block is being walked over or is being placed
   *
   * @return step sound
   */
  public SoundEffect getStepSound() {
    return this.stepSound;
  }

  @Override
  public boolean isPlacementObstacle() {
    return true;
  }

  @Override
  public boolean hasPhysics() {
    return false;
  }

  @Override
  public boolean hasNBTData() {
    return false;
  }

  @Override
  public int getDamage() {
    return this.meleeDamage;
  }

  @Override
  public VanillaBlockMaterial setDamage(int damage) {
    this.meleeDamage = damage;
    return this;
  }

  /**
   * Gets the instrument note blocks play with this block material below
   *
   * @return the instrument
   */
  public Instrument getInstrument() {
    return Instrument.PIANO;
  }

  @Override
  public boolean isRedstoneConductor() {
    return false;
  }

  @Override
  public short getIndirectRedstonePower(Block block, BlockFace direction, RedstonePowerMode powerMode) {
    return this.getRedstonePower(block);
  }

  @Override
  public final boolean hasIndirectRedstonePower(Block block, BlockFace direction, RedstonePowerMode powerMode) {
    return this.getIndirectRedstonePower(block, direction, powerMode) > 0;
  }

  @Override
  public final short getRedstonePower(Block block) {
    return this.getRedstonePower(block, RedstonePowerMode.ALL);
  }

  @Override
  public short getRedstonePower(Block block, RedstonePowerMode powerMode) {
    if (!this.isRedstoneConductor()) {
      return REDSTONE_POWER_MIN;
    }

    short power = 0;
    Block neigh;
    BlockMaterial mat;
    for (BlockFace face : BlockFaces.NESWBT) {
      neigh = block.translate(face);
      mat = neigh.getMaterial();
      if (mat instanceof RedstoneSource) {
        power = (short) Math.max(power, ((RedstoneSource) mat).getDirectRedstonePower(neigh, face.getOpposite(), powerMode));
      }
    }
    return power;
  }

  @Override
  public final boolean hasRedstonePower(Block block) {
    return this.hasRedstonePower(block, RedstonePowerMode.ALL);
  }

  @Override
  public final boolean hasRedstonePower(Block block, RedstonePowerMode powerMode) {
    return this.getRedstonePower(block, powerMode) > 0;
  }

  public VanillaBlockMaterial setResistance(Float newResistance) {
    resistance = newResistance;
    return this;
  }

  public float getResistance() {
    return resistance;
  }

  /**
   * Gets whether this block material can support the attachable block material to the face given
   *
   * @param material to attach
   * @param face of this block to attach to
   */
  public boolean canSupport(BlockMaterial material, BlockFace face) {
    return false;
  }

  /**
   * Gets the move reaction of block material for the block specified
   *
   * @param block that is being moved
   * @return the move reaction
   */
  public MoveReaction getMoveReaction(Block block) {
    return MoveReaction.BREAK;
  }

  /**
   * Gets whether this block material cancels block placement when clicked
   */
  public boolean isPlacementSuppressed() {
    return false;
  }

  /**
   * Gets if this material is a liquid obstacle
   *
   * @return True if it can stop liquids, False if this material gets destroyed
   */
  public boolean isLiquidObstacle() {
    return this.liquidObstacle;
  }

  /**
   * Sets if this material is a liquid obstacle
   *
   * @param state True to make it an obstacle, False to let liquids destroy this block
   */
  public VanillaBlockMaterial setLiquidObstacle(boolean state) {
    this.liquidObstacle = state;
    return this;
  }

  private void updateDropFlags() {
    this.drops.NOT_CREATIVE.clearFlags();
    this.drops.NOT_CREATIVE.addFlags(PlayerFlags.CREATIVE.NOT);
    if (this.miningLevel != null && this.miningLevel != ToolLevel.NONE) {
      this.drops.NOT_CREATIVE.addFlags(this.miningLevel.getDropFlag());
      Flag[] typeFlags = new Flag[this.miningTypes.size()];
      int i = 0;
      for (ToolType type : this.miningTypes) {
        typeFlags[i] = type.getDropFlag();
        i++;
      }
      this.drops.NOT_CREATIVE.addFlags(new FlagBundle(typeFlags));
    }
  }

  public VanillaBlockMaterial setMiningLevel(ToolLevel miningLevel) {
    this.miningLevel = miningLevel;
    updateDropFlags();
    return this;
  }

  /**
   * Adds the mining type to this Block material<br> This type will be used when checking for drops and when calculating the digging time
   *
   * @param miningType to add
   * @return this material
   */
  public VanillaBlockMaterial addMiningType(ToolType miningType) {
    this.miningTypes.add(miningType);
    updateDropFlags();
    return this;
  }

  /**
   * Gets if the mining type is set for this Block material<br> This type is used when checking for drops and when calculating digging time
   *
   * @return True if the tool type is set
   */
  public boolean isMiningType(ToolType toolType) {
    return this.miningTypes.contains(toolType);
  }

  /**
   * Gets the mining level required for breaking this BlockMaterial<br> This level has to be met to spawn drops
   *
   * @return mining level
   */
  public ToolLevel getMiningLevel() {
    return miningLevel;
  }

  /**
   * Gets the drops for this block material
   *
   * @return the drops
   */
  public BlockDrops getDrops() {
    return this.drops;
  }

  // Utilities
  private static final EffectRange FARMLAND_CHECK_RANGE = new CuboidEffectRange(-1, -1, -1, 1, -1, 1);

  /**
   * Plays a block action for this type of Block Material
   *
   * @param block to play at
   * @param arg1 for the action
   * @param arg2 for the action
   */
  public static void playBlockAction(Block block, byte arg1, byte arg2) {
    BlockActionEvent event = new BlockActionEvent(block, block.getMaterial(), arg1, arg2);
    for (Player player : block.getChunk().getObservingPlayers()) {
      player.getNetwork().callProtocolEvent(event, player);
    }
  }

  /**
   * Gets if rain is falling nearby the block specified
   *
   * @param block to check it nearby of
   * @return True if it is raining, False if not
   */
  public static boolean hasRainNearby(Block block) {
    Sky sky = block.getWorld().get(Sky.class);
    if (sky != null && sky.hasWeather()) {
      if (sky.getWeatherSimulator().isRainingAt(block.getX(), block.getY(), block.getZ(), false)) {
        for (BlockFace face : BlockFaces.NESW) {
          if (block.translate(face).isAtSurface()) {
            return true;
          }
        }
      }
    }
    return false;
  }

  /**
   * Gets if rain is falling on top of the block specified
   *
   * @param block to check
   * @return True if rain is falling on the Block, false if not
   */
  public static boolean isRaining(Block block) {
    return block.getWorld().getData().get(VanillaData.WORLD_WEATHER).isRaining() && block.isAtSurface();
  }

  /**
   * Gets the chance of a crop block growing<br> The higher the value, the lower the chance.
   *
   * @param block to check
   * @return the growth chance
   */
  public static int getCropGrowthChance(Block block) {
    BlockMaterial material = block.getMaterial();
    float rate = 1.0f;
    float farmLandRate;
    Block rel;
    for (IntVector3 coord : FARMLAND_CHECK_RANGE) {
      rel = block.translate(coord);
      if (rel.isMaterial(VanillaMaterials.FARMLAND)) {
        if (VanillaMaterials.FARMLAND.isWet(rel)) {
          farmLandRate = 3.0f;
        } else {
          farmLandRate = 1.0f;
        }
        if (rel.getX() != 0 && rel.getZ() != 0) {
          // this is farmland at a neighbor
          farmLandRate /= 4.0f;
        }
        rate += farmLandRate;
      }
    }

    // Half, yes or no? Check for neighboring crops
    if (block.translate(-1, 0, -1).isMaterial(material) || block.translate(1, 0, 1).isMaterial(material)
        || block.translate(-1, 0, 1).isMaterial(material) || block.translate(1, 0, -1).isMaterial(material)) {
      return (int) (50f / rate);
    }
    if ((block.translate(-1, 0, 0).isMaterial(material) || block.translate(1, 0, 0).isMaterial(material))
        && (block.translate(0, 0, -1).isMaterial(material) || block.translate(0, 0, 1).isMaterial(material))) {
      return (int) (50f / rate);
    }
    return (int) (25f / rate);
  }

  /**
   * Gets a vertical column of chunks
   *
   * @param middle chunk
   * @return list of chunks in the column
   */
  public static List<Chunk> getChunkColumn(Chunk middle) {
    Chunk top = middle;
    Chunk tmp;
    while (true) {
      tmp = top.getRelative(BlockFace.TOP, LoadOption.NO_LOAD);
      if (tmp != null && tmp.isLoaded()) {
        top = tmp;
      } else {
        break;
      }
    }
    List<Chunk> rval = new ArrayList<Chunk>();
    while (top != null && top.isLoaded()) {
      rval.add(top);
      top = top.getRelative(BlockFace.BOTTOM, LoadOption.NO_LOAD);
    }
    return rval;
  }

  @Override
  public void onInteractBy(Entity entity, Block block, Action type, BlockFace clickedFace) {
    EntityInteractBlockEvent event;
    if (entity instanceof Player) {
      event = new PlayerInteractBlockEvent((Player) entity, block, block.getPosition(), clickedFace, type);
    } else {
      event = new EntityInteractBlockEvent(entity, block, block.getPosition(), clickedFace);
    }
    if (Spout.getEventManager().callEvent(event).isCancelled()) {
      return;
    }
    super.onInteract(entity, block, type, clickedFace);
    for (Class<? extends BlockComponent> c : getComponents()) {
      BlockComponent get = block.get(c);
      if (get != null) {
        get.onInteract(event);
      }
    }
  }
}
TOP

Related Classes of org.spout.vanilla.material.VanillaBlockMaterial

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.