mirror of https://github.com/Minestom/Minestom.git
244 lines
7.1 KiB
Java
244 lines
7.1 KiB
Java
package net.minestom.server.entity;
|
|
|
|
import net.minestom.server.entity.metadata.item.ItemEntityMeta;
|
|
import net.minestom.server.event.EventDispatcher;
|
|
import net.minestom.server.event.entity.EntityItemMergeEvent;
|
|
import net.minestom.server.instance.Chunk;
|
|
import net.minestom.server.instance.Instance;
|
|
import net.minestom.server.item.ItemStack;
|
|
import net.minestom.server.item.StackingRule;
|
|
import net.minestom.server.utils.Position;
|
|
import net.minestom.server.utils.time.Cooldown;
|
|
import net.minestom.server.utils.time.TimeUnit;
|
|
import net.minestom.server.utils.time.UpdateOption;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* Represents an item on the ground.
|
|
*/
|
|
public class ItemEntity extends Entity {
|
|
|
|
/**
|
|
* Used to slow down the merge check delay
|
|
*/
|
|
private static UpdateOption mergeUpdateOption = new UpdateOption(10, TimeUnit.TICK);
|
|
|
|
/**
|
|
* The last time that this item has checked his neighbors for merge
|
|
*/
|
|
private long lastMergeCheck;
|
|
|
|
private ItemStack itemStack;
|
|
|
|
private boolean pickable = true;
|
|
private boolean mergeable = true;
|
|
private float mergeRange = 1;
|
|
|
|
private long spawnTime;
|
|
private long pickupDelay;
|
|
|
|
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition) {
|
|
super(EntityType.ITEM, spawnPosition);
|
|
setItemStack(itemStack);
|
|
setGravity(0.02f, 0.04f, 1.96f);
|
|
setBoundingBox(0.25f, 0.25f, 0.25f);
|
|
}
|
|
|
|
public ItemEntity(@NotNull ItemStack itemStack, @NotNull Position spawnPosition, @Nullable Instance instance) {
|
|
this(itemStack, spawnPosition);
|
|
|
|
if (instance != null) {
|
|
setInstance(instance);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the update option for the merging feature.
|
|
*
|
|
* @return the merge update option
|
|
*/
|
|
@Nullable
|
|
public static UpdateOption getMergeUpdateOption() {
|
|
return mergeUpdateOption;
|
|
}
|
|
|
|
/**
|
|
* Changes the merge update option.
|
|
* Can be set to null to entirely remove the delay.
|
|
*
|
|
* @param mergeUpdateOption the new merge update option
|
|
*/
|
|
public static void setMergeUpdateOption(@Nullable UpdateOption mergeUpdateOption) {
|
|
ItemEntity.mergeUpdateOption = mergeUpdateOption;
|
|
}
|
|
|
|
@Override
|
|
public void update(long time) {
|
|
if (isMergeable() && isPickable() &&
|
|
(mergeUpdateOption == null || !Cooldown.hasCooldown(time, lastMergeCheck, mergeUpdateOption))) {
|
|
this.lastMergeCheck = time;
|
|
|
|
final Chunk chunk = instance.getChunkAt(getPosition());
|
|
final Set<Entity> entities = instance.getChunkEntities(chunk);
|
|
for (Entity entity : entities) {
|
|
if (entity instanceof ItemEntity) {
|
|
|
|
// Do not merge with itself
|
|
if (entity == this)
|
|
continue;
|
|
|
|
final ItemEntity itemEntity = (ItemEntity) entity;
|
|
if (!itemEntity.isPickable() || !itemEntity.isMergeable())
|
|
continue;
|
|
|
|
// Too far, do not merge
|
|
if (getDistance(itemEntity) > mergeRange)
|
|
continue;
|
|
|
|
final ItemStack itemStackEntity = itemEntity.getItemStack();
|
|
|
|
final StackingRule stackingRule = itemStack.getStackingRule();
|
|
final boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity);
|
|
|
|
if (!canStack)
|
|
continue;
|
|
|
|
final int totalAmount = stackingRule.getAmount(itemStack) + stackingRule.getAmount(itemStackEntity);
|
|
final boolean canApply = stackingRule.canApply(itemStack, totalAmount);
|
|
|
|
if (!canApply)
|
|
continue;
|
|
|
|
final ItemStack result = stackingRule.apply(itemStack, totalAmount);
|
|
|
|
EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity, result);
|
|
EventDispatcher.callCancellable(entityItemMergeEvent, () -> {
|
|
setItemStack(entityItemMergeEvent.getResult());
|
|
itemEntity.remove();
|
|
});
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void spawn() {
|
|
this.spawnTime = System.currentTimeMillis();
|
|
}
|
|
|
|
@Override
|
|
public @NotNull ItemEntityMeta getEntityMeta() {
|
|
return (ItemEntityMeta) super.getEntityMeta();
|
|
}
|
|
|
|
/**
|
|
* Gets the item stack on ground.
|
|
*
|
|
* @return the item stack
|
|
*/
|
|
@NotNull
|
|
public ItemStack getItemStack() {
|
|
return itemStack;
|
|
}
|
|
|
|
/**
|
|
* Changes the item stack on ground.
|
|
*
|
|
* @param itemStack the item stack
|
|
*/
|
|
public void setItemStack(@NotNull ItemStack itemStack) {
|
|
this.itemStack = itemStack;
|
|
getEntityMeta().setItem(itemStack);
|
|
}
|
|
|
|
/**
|
|
* Gets if the item is currently pickable.
|
|
* <p>
|
|
* {@link #setPickable(boolean)} needs to be true and the delay {@link #getPickupDelay()}
|
|
* to be long gone.
|
|
*
|
|
* @return true if the item is pickable, false otherwise
|
|
*/
|
|
public boolean isPickable() {
|
|
return pickable && (System.currentTimeMillis() - getSpawnTime() >= pickupDelay);
|
|
}
|
|
|
|
/**
|
|
* Makes the item pickable.
|
|
*
|
|
* @param pickable true to make the item pickable, false otherwise
|
|
*/
|
|
public void setPickable(boolean pickable) {
|
|
this.pickable = pickable;
|
|
}
|
|
|
|
/**
|
|
* Gets if the item is mergeable.
|
|
*
|
|
* @return true if the entity is mergeable, false otherwise
|
|
*/
|
|
public boolean isMergeable() {
|
|
return mergeable;
|
|
}
|
|
|
|
/**
|
|
* When set to true, close {@link ItemEntity} will try to merge together as a single entity
|
|
* when their {@link #getItemStack()} is similar and allowed to stack together.
|
|
*
|
|
* @param mergeable should the entity merge with other {@link ItemEntity}
|
|
*/
|
|
public void setMergeable(boolean mergeable) {
|
|
this.mergeable = mergeable;
|
|
}
|
|
|
|
/**
|
|
* Gets the merge range.
|
|
*
|
|
* @return the merge range
|
|
*/
|
|
public float getMergeRange() {
|
|
return mergeRange;
|
|
}
|
|
|
|
/**
|
|
* Changes the merge range.
|
|
*
|
|
* @param mergeRange the merge range
|
|
*/
|
|
public void setMergeRange(float mergeRange) {
|
|
this.mergeRange = mergeRange;
|
|
}
|
|
|
|
/**
|
|
* Gets the pickup delay in milliseconds, defined by {@link #setPickupDelay(long, TimeUnit)}.
|
|
*
|
|
* @return the pickup delay
|
|
*/
|
|
public long getPickupDelay() {
|
|
return pickupDelay;
|
|
}
|
|
|
|
/**
|
|
* Sets the pickup delay of the ItemEntity.
|
|
*
|
|
* @param delay the pickup delay
|
|
* @param timeUnit the unit of the delay
|
|
*/
|
|
public void setPickupDelay(long delay, @NotNull TimeUnit timeUnit) {
|
|
this.pickupDelay = timeUnit.toMilliseconds(delay);
|
|
}
|
|
|
|
/**
|
|
* Used to know if the ItemEntity can be pickup.
|
|
*
|
|
* @return the time in milliseconds since this entity has spawn
|
|
*/
|
|
public long getSpawnTime() {
|
|
return spawnTime;
|
|
}
|
|
}
|