Skip to content

Commit

Permalink
feat: implement block break time calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed Jun 10, 2024
1 parent 004e59d commit 86699b5
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@
import org.allaymc.api.block.component.BlockComponent;
import org.allaymc.api.block.function.*;
import org.allaymc.api.block.property.type.BlockPropertyType;
import org.allaymc.api.block.type.BlockState;
import org.allaymc.api.block.type.BlockType;
import org.allaymc.api.block.type.BlockTypes;
import org.allaymc.api.container.FullContainerType;
import org.allaymc.api.container.impl.PlayerArmorContainer;
import org.allaymc.api.data.VanillaItemTags;
import org.allaymc.api.entity.Entity;
import org.allaymc.api.entity.component.common.EntityContainerHolderComponent;
import org.allaymc.api.entity.effect.type.EffectConduitPowerType;
import org.allaymc.api.entity.effect.type.EffectHasteType;
import org.allaymc.api.item.ItemStack;
import org.allaymc.api.item.enchantment.type.EnchantmentAquaAffinityType;
import org.allaymc.api.item.enchantment.type.EnchantmentEfficiencyType;
import org.allaymc.api.item.tag.ItemTag;
import org.allaymc.api.world.Dimension;

/**
Expand Down Expand Up @@ -33,4 +46,85 @@ default <DATATYPE> void updateBlockProperty(BlockPropertyType<DATATYPE> property
chunk.setBlockState(xIndex, y, zIndex, newBlockState, layer);
chunk.sendChunkPacket(Dimension.createBlockUpdatePacket(newBlockState, x, y, z, layer));
}

default double calculateBreakTime(BlockState blockState, ItemStack usedItem, Entity entity) {
checkBlockType(blockState);
double blockHardness = blockState.getBlockAttributes().hardness();
if (blockHardness == 0) return 0;
boolean isCorrectTool = isCorrectTool(blockState, usedItem);
boolean hasAquaAffinity = false;
boolean isInWater = false;
boolean isOnGround = true;
int hasteEffectLevel = 0;
int miningFatigueLevel = 0;
int efficiencyLevel = 0;

if (entity != null) {
isInWater = entity.isInWater();
isOnGround = entity.isOnGround();
hasteEffectLevel = entity.getEffectLevel(EffectHasteType.HASTE_TYPE);
// 潮涌核心保证至少两级的急速效果
if (entity.hasEffect(EffectConduitPowerType.CONDUIT_POWER_TYPE)) {
hasteEffectLevel = Integer.max(hasteEffectLevel, 2);
}
miningFatigueLevel = entity.getEffectLevel(EffectHasteType.HASTE_TYPE);
if (entity instanceof EntityContainerHolderComponent containerHolder) {
if (containerHolder.hasContainer(FullContainerType.ARMOR)) {
hasAquaAffinity = containerHolder.getContainer(FullContainerType.ARMOR).getItemStack(0).hasEnchantment(EnchantmentAquaAffinityType.AQUA_AFFINITY_TYPE);
}
if (containerHolder.hasContainer(FullContainerType.PLAYER_INVENTORY)) {
efficiencyLevel = containerHolder.getContainer(FullContainerType.PLAYER_INVENTORY).getItemInHand().getEnchantmentLevel(EnchantmentEfficiencyType.EFFICIENCY_TYPE);
}
}
}

// Calculate break time
double speed = 1.0d / blockHardness;
if (isCorrectTool) {
// 若是正确的工具,初始速度除以1.5
speed /= 1.5d;
// 工具等级(木制,石制,铁制,etc...)加成
speed *= toolBreakTimeBonus(usedItem, blockState);
// 工具效率附魔加成
speed += speedBonusByEfficiency(efficiencyLevel);
} else {
// 若不是正确的工具,初始速度除以5
speed /= 5.0d;
}
// 实体急迫药水效果加成
speed *= 1.0d + (0.2d * hasteEffectLevel);
// 实体挖掘疲劳效果负加成
if (miningFatigueLevel != 0) speed /= Math.pow(miningFatigueLevel, 3);
// 在水中但是没有水下速挖掘效果
if (isInWater && !hasAquaAffinity) speed *= 0.2d;
// 在半空中
if (!isInWater && !isOnGround) speed *= 0.2d;
return 1.0d / speed;
}

private static double speedBonusByEfficiency(int efficiencyLevel) {
if (efficiencyLevel == 0) return 0;
return efficiencyLevel * efficiencyLevel + 1;
}

private double toolBreakTimeBonus(ItemStack usedItem, BlockState blockState) {
// TODO: 实现剑破坏蜘蛛网,剪刀破坏羊毛和树叶和蜘蛛网的加速
var itemType = usedItem.getItemType();
if (itemType.hasItemTag(VanillaItemTags.GOLDEN_TIER)) return 12.0;
if (itemType.hasItemTag(VanillaItemTags.NETHERITE_TIER)) return 9.0;
if (itemType.hasItemTag(VanillaItemTags.DIAMOND_TIER)) return 8.0;
if (itemType.hasItemTag(VanillaItemTags.IRON_TIER)) return 6.0;
if (itemType.hasItemTag(VanillaItemTags.STONE_TIER)) return 4.0;
if (itemType.hasItemTag(VanillaItemTags.WOODEN_TIER)) return 2.0;
return 1.0;
}

default boolean isCorrectTool(BlockState blockState, ItemStack usedItem) {
checkBlockType(blockState);
return false;
}

private void checkBlockType(BlockState blockState) {
if (blockState.getBlockType() != getBlockType()) throw new IllegalArgumentException("Block type is not match! Expected: " + getBlockType().getIdentifier() + ", actual: " + blockState.getBlockType().getIdentifier());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public BaseContainerHolder(Container... containers) {
return Collections.unmodifiableMap(typeToContainer);
}

@Override
public boolean hasContainer(FullContainerType<?> type) {
return typeToContainer.containsKey(type);
}

@Override
public <T extends Container> T getContainer(FullContainerType<T> type) {
return (T) typeToContainer.get(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public interface ContainerHolder {
@UnmodifiableView
Map<FullContainerType<?>, Container> getContainers();

boolean hasContainer(FullContainerType<?> type);

<T extends Container> T getContainer(FullContainerType<T> type);

<T extends Container> T getContainerBySlotType(ContainerSlotType slotType);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.allaymc.api.entity.component.common;

import org.allaymc.api.block.data.BlockFace;
import org.allaymc.api.block.type.BlockType;
import org.allaymc.api.block.type.BlockTypes;
import org.allaymc.api.command.CommandSender;
import org.allaymc.api.entity.Entity;
import org.allaymc.api.entity.component.EntityComponent;
Expand Down Expand Up @@ -203,6 +205,10 @@ default NbtMap saveNBTWithoutPos() {

void onFall();

boolean hasEffect(EffectType effectType);

int getEffectLevel(EffectType effectType);

void addEffect(EffectInstance effectInstance);

void removeEffect(EffectType effectType);
Expand Down Expand Up @@ -333,4 +339,24 @@ default boolean canCriticalAttack() {

@UnmodifiableView
Set<String> getTags();

default boolean isInWater() {
var loc = getLocation();
int fx = (int) loc.x();
int fy = (int) loc.y();
int fz = (int) loc.z();
var blockType = getDimension().getBlockState(fx, fy, fz).getBlockType();
if (isWaterType(blockType)) {
return true;
}
blockType = getDimension().getBlockState(fx, fy, fz, 1).getBlockType();
if (isWaterType(blockType)) {
return true;
}
return false;
}

private static boolean isWaterType(BlockType<?> blockType) {
return blockType == BlockTypes.FLOWING_WATER_TYPE || blockType == BlockTypes.WATER_TYPE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.allaymc.api.entity.interfaces.EntityPlayer;
import org.allaymc.api.item.ItemStack;
import org.allaymc.api.item.component.ItemComponent;
import org.allaymc.api.item.enchantment.EnchantmentType;
import org.allaymc.api.item.type.ItemType;
import org.allaymc.api.world.Dimension;
import org.cloudburstmc.nbt.NbtMap;
Expand Down Expand Up @@ -109,4 +110,10 @@ default NbtMap saveNBT() {
}

float calculateAttackDamage();

boolean hasEnchantment(EnchantmentType enchantmentType);

short getEnchantmentLevel(EnchantmentType enchantmentType);

void addEnchantment(EnchantmentType enchantmentType, short level);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.allaymc.api.block.function.Place;
import org.allaymc.api.block.type.BlockState;
import org.allaymc.api.block.type.BlockType;
import org.allaymc.api.entity.Entity;
import org.allaymc.api.utils.Identifier;
import org.allaymc.api.component.annotation.ComponentIdentifier;
import org.allaymc.api.component.annotation.Manager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,17 @@ public void onFall() {
this.fallDistance = 0;
}

@Override
public boolean hasEffect(EffectType effectType) {
return effects.containsKey(effectType);
}

@Override
public int getEffectLevel(EffectType effectType) {
var effect = effects.get(effectType);
return effect == null ? 0 : effect.getAmplifier() + 1;
}

@Override
public void addEffect(EffectInstance effectInstance) {
var old = effects.put(effectInstance.getType(), effectInstance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.allaymc.api.block.data.BlockFace;
import org.allaymc.api.block.type.BlockState;
import org.allaymc.api.block.type.BlockType;
import org.allaymc.api.item.enchantment.SimpleEnchantmentInstance;
import org.allaymc.api.utils.Identifier;
import org.allaymc.api.component.annotation.ComponentIdentifier;
import org.allaymc.api.component.annotation.ComponentedObject;
Expand Down Expand Up @@ -325,4 +326,20 @@ public ItemStack copy() {
public float calculateAttackDamage() {
return attributeComponent.getItemAttributes().attackDamage();
}

@Override
public boolean hasEnchantment(EnchantmentType enchantmentType) {
return enchantments.containsKey(enchantmentType);
}

@Override
public short getEnchantmentLevel(EnchantmentType enchantmentType) {
var instance = enchantments.get(enchantmentType);
return instance == null ? 0 : instance.getLevel();
}

@Override
public void addEnchantment(EnchantmentType enchantmentType, short level) {
enchantments.put(enchantmentType, new SimpleEnchantmentInstance(enchantmentType, level));
}
}
Loading

0 comments on commit 86699b5

Please sign in to comment.