/*
* 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.component.entity.misc;
import org.spout.api.geo.discrete.Point;
import org.spout.api.material.Material;
import org.spout.math.GenericMath;
import org.spout.vanilla.component.entity.VanillaEntityComponent;
import org.spout.vanilla.data.Animation;
import org.spout.vanilla.data.configuration.VanillaConfiguration;
import org.spout.vanilla.data.tool.ToolType;
import org.spout.vanilla.event.entity.network.EntityAnimationEvent;
import org.spout.vanilla.event.material.network.BlockBreakAnimationEvent;
import org.spout.vanilla.material.VanillaBlockMaterial;
import org.spout.vanilla.material.item.tool.MiningTool;
/**
* Component that mainly handles the block breaking animation.
*/
public class Digging extends VanillaEntityComponent {
private boolean isDigging;
protected Point diggingPosition;
protected long diggingStartTime;
protected int miningDamagePosition = 0;
protected long previousDiggingTime = 0;
protected final int miningDamageAllowance = VanillaConfiguration.PLAYER_SPEEDMINING_PREVENTION_ALLOWANCE.getInt();
protected final int miningDamagePeriod = VanillaConfiguration.PLAYER_SPEEDMINING_PREVENTION_PERIOD.getInt();
protected int[] miningDamage;
private byte amount = 0;
private int blockBroken = 0;
private float timer = 0f, separator = 0f;
public boolean canTick() {
return isDigging;
}
public void onTick(float dt) {
if (timer >= separator) {
getOwner().getNetwork().callProtocolEvent(new BlockBreakAnimationEvent(getOwner(), diggingPosition, amount++), true);
timer = 0;
}
timer += dt;
}
/**
* Returns the digging state of the entity
*
* @return true if player is digging
*/
public boolean isDigging() {
return isDigging;
}
/**
* Sets isDigging true and records start time, unless already digging
*
* @return true if successful
*/
public boolean startDigging(Point position, Material tool) {
if (getOwner().getPhysics().getPosition().getDistance(position) > 6) { // TODO: Actually get block reach from somewhere instead of just using 6
return false;
}
VanillaBlockMaterial block = (VanillaBlockMaterial) position.getBlock().getMaterial();
float modifier = 1f, multiplicator = 1.5f;
ToolType type = null;
MiningTool mining = null;
if (tool instanceof MiningTool) {
mining = (MiningTool) tool;
type = mining.getToolType();
}
if (block.isMiningType(type)) {
if (mining != null) {
modifier = mining.getDiggingSpeed();
}
} else {
multiplicator = 5f;
}
byte maxAmount = 8;
separator = ((block.getHardness() * multiplicator) / modifier) / maxAmount;
amount = 0;
timer = 0;
isDigging = true;
diggingPosition = position;
diggingStartTime = System.currentTimeMillis();
return true;
}
/**
* Sets isDigging false and records total time, unless the dig was invalid/never started.
*
* @return true if successful
*/
public boolean stopDigging(Point position, boolean blockBreak) {
if (!isDigging) {
return false;
}
if (blockBreak) {
setBlockBroken(getBlockBroken() + 1);
}
previousDiggingTime = getDiggingTime();
isDigging = false;
getOwner().getNetwork().callProtocolEvent(new BlockBreakAnimationEvent(getOwner(), diggingPosition, (byte) -1));
getOwner().getNetwork().callProtocolEvent(new EntityAnimationEvent(getOwner(), Animation.NONE));
return position.equals(diggingPosition);
}
/**
* Gets time spent digging
*
* @return time spent digging
*/
public long getDiggingTime() {
if (!isDigging) {
return previousDiggingTime;
}
// Is this correct?
return System.currentTimeMillis() - diggingStartTime;
}
/**
* Gets last time spent digging in real(client) ticks
*
* @return ticks spent digging
*/
public long getDiggingTicks() {
return getDiggingTime() / 50;
}
/**
* Adds and checks mining speed for cheating.
*
* @param damageRemaining Remaining damage on block
* @return false if player is cheating
*/
public boolean addAndCheckMiningSpeed(int damageRemaining) {
if (!VanillaConfiguration.PLAYER_SPEEDMINING_PREVENTION_ENABLED.getBoolean()) {
return true;
}
miningDamage[miningDamagePosition++] = damageRemaining;
if (miningDamagePosition >= miningDamagePeriod) {
miningDamagePosition = 0;
}
return checkMiningSpeed();
}
/**
* Checks mining speed for cheating.
*
* @return false if player is cheating
*/
public boolean checkMiningSpeed() {
return GenericMath.mean(miningDamage) <= miningDamageAllowance;
}
public int getBlockBroken() {
return blockBroken;
}
public void setBlockBroken(int blockBroken) {
this.blockBroken = blockBroken;
}
}