ModernLifePatch/src-source/main/java/com/dairymoose/modernlife/items/ChainsawItem.java
2024-10-26 09:40:21 +08:00

432 lines
21 KiB
Java

package com.dairymoose.modernlife.items;
import com.dairymoose.modernlife.core.CustomBlocks;
import com.dairymoose.modernlife.core.ModernLifeCommon;
import com.dairymoose.modernlife.core.ModernLifeConfig;
import com.dairymoose.modernlife.core.ModernLifeNetwork;
import com.dairymoose.modernlife.network.play.client.ServerboundChainsawTargetPacket;
import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/* loaded from: outputsrg.jar:com/dairymoose/modernlife/items/ChainsawItem.class */
public class ChainsawItem extends DiggerItem {
private final ScheduledExecutorService scheduler;
boolean isWieldingChainsaw;
private int chainsawStartTick;
private static final int CHAINSAW_START_PAUSE = 6;
private static final int CHAINSAW_IDLE_PAUSE = 18;
private static final Logger LOGGER = LogManager.getLogger();
private static final Set<Material> CHAINSAW_MATERIALS = Sets.newHashSet(new Material[]{Material.LEAVES, Material.WOOD, Material.NETHER_WOOD, Material.PLANT, Material.REPLACEABLE_PLANT, Material.BAMBOO, Material.VEGETABLE});
private static final Set<Block> CHAINSAW_BLOCKS = Sets.newHashSet(new Block[]{Blocks.WARPED_WART_BLOCK, Blocks.NETHER_WART_BLOCK, Blocks.COBWEB});
private static final Set<Block> OTHER_DIGGABLE_BLOCKS = Sets.newHashSet(new Block[]{Blocks.LADDER, Blocks.SCAFFOLDING, Blocks.OAK_BUTTON, Blocks.SPRUCE_BUTTON, Blocks.BIRCH_BUTTON, Blocks.JUNGLE_BUTTON, Blocks.DARK_OAK_BUTTON, Blocks.ACACIA_BUTTON, Blocks.CRIMSON_BUTTON, Blocks.WARPED_BUTTON, Blocks.NETHER_WART_BLOCK, Blocks.COBWEB});
private static final Set<Block> CHAINSAW_DIGGABLE_SET = Sets.union(CHAINSAW_BLOCKS, OTHER_DIGGABLE_BLOCKS);
public static Map<Player, MiningInfo> mineMap = new HashMap();
/* loaded from: outputsrg.jar:com/dairymoose/modernlife/items/ChainsawItem$MiningInfo.class */
public static class MiningInfo {
public float miningProgress;
public BlockPos pos;
public HitResult rayTrace;
}
public ChainsawItem(Tier tier, float p_i48530_2_, float p_i48530_3_, Properties p_i48530_4_) {
super(p_i48530_2_, p_i48530_3_, tier, BlockTags.MINEABLE_WITH_AXE, p_i48530_4_);
this.scheduler = Executors.newScheduledThreadPool(3);
this.isWieldingChainsaw = false;
this.chainsawStartTick = 0;
}
public float getDestroySpeed(ItemStack p_150893_1_, BlockState p_150893_2_) {
Material material = p_150893_2_.m_60767_();
float webMult = 1.0f;
if (p_150893_2_.is(Blocks.COBWEB)) {
webMult = 2.0f;
}
return (CHAINSAW_MATERIALS.contains(material) || CHAINSAW_DIGGABLE_SET.contains(p_150893_2_.getBlock())) ? webMult * this.speed : super.getDestroySpeed(p_150893_1_, p_150893_2_);
}
void chainsawAttack(Level world, Player player, ItemStack itemStack, Entity targetEntity, Vec3 loc) {
LivingEntity livingEntity = (LivingEntity) targetEntity;
if (livingEntity.isAlive() && livingEntity.isAttackable()) {
int initialInvulnerableTime = livingEntity.invulnerableTime;
AttributeInstance kbResist = livingEntity.getAttribute(Attributes.KNOCKBACK_RESISTANCE);
double kbResistInitial = kbResist.getBaseValue();
try {
double pickRange = player.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue();
double chainsawRange = pickRange * 1.0d;
double chainsawRangeSqr = chainsawRange * chainsawRange;
if (livingEntity.distanceToSqr(player.getEyePosition(1.0f)) <= chainsawRangeSqr && (world instanceof ServerLevel)) {
livingEntity.invulnerableTime = 0;
kbResist.setBaseValue(1.0d);
if (livingEntity.hurt(DamageSource.playerAttack(player), 1.87f)) {
((ServerLevel) world).sendParticles(ParticleTypes.CRIMSON_SPORE, livingEntity.getX() + ((Math.random() * 0.5d) - 0.25d), loc.y, livingEntity.getZ() + ((Math.random() * 0.5d) - 0.25d), 30, 0.0d, 0.0d, 0.0d, 0.0d);
int durabilityDamage = 26;
Integer chainsawConfigDamage = (Integer) ModernLifeConfig.SERVER.chainsawDurabilityDamageOnAttack.get();
if (chainsawConfigDamage != null) {
durabilityDamage = chainsawConfigDamage.intValue();
}
itemStack.hurtAndBreak(durabilityDamage, player, t -> {
});
if (itemStack.getCount() <= 0) {
return;
}
}
}
livingEntity.invulnerableTime = initialInvulnerableTime;
kbResist.setBaseValue(kbResistInitial);
} finally {
livingEntity.invulnerableTime = initialInvulnerableTime;
kbResist.setBaseValue(kbResistInitial);
}
}
}
private void chainsawSound(Level world, Player player, int count, float pitchMod) {
if (count % 4 == 0) {
world.playSound(player, player.blockPosition(), CustomBlocks.SOUND_CHAINSAW_RUNNING.get(), SoundSource.BLOCKS, 0.15f, 0.9f + pitchMod);
}
}
private boolean shouldPlayChainsawIdleSound() {
boolean shouldPlay = true;
Boolean shouldPlayConfig = (Boolean) ModernLifeConfig.CLIENT.chainsawPlaysIdleSound.get();
if (shouldPlayConfig != null) {
shouldPlay = shouldPlayConfig.booleanValue();
}
return shouldPlay;
}
private void chainsawStartSound(Level world, Player player, int count) {
if (shouldPlayChainsawIdleSound()) {
world.playSound(player, player.blockPosition(), CustomBlocks.SOUND_CHAINSAW_START.get(), SoundSource.BLOCKS, 0.15f, 1.0f);
}
}
private void chainsawIdleSound(Level world, Player player, int count) {
if (count % 4 == 0 && shouldPlayChainsawIdleSound()) {
world.playSound(player, player.blockPosition(), CustomBlocks.SOUND_CHAINSAW_IDLE.get(), SoundSource.BLOCKS, 0.04f, 1.0f);
}
}
private void chainsawStopSound(Level world, Player player, int count) {
if (shouldPlayChainsawIdleSound()) {
world.playSound(player, player.blockPosition(), CustomBlocks.SOUND_CHAINSAW_STOP.get(), SoundSource.BLOCKS, 0.15f, 1.0f);
}
}
@OnlyIn(Dist.CLIENT)
public void inventoryTick(ItemStack itemStack, Level level, Entity entity, int slot, boolean isMainHand) {
if (level.isClientSide && (entity instanceof LivingEntity)) {
LivingEntity le = (LivingEntity) entity;
if (le.getId() == Minecraft.getInstance().player.getId()) {
LocalPlayer localPlayer = Minecraft.getInstance().player;
ItemStack mainHandItem = le.getMainHandItem();
ItemStack offHandItem = le.getOffhandItem();
if (!this.isWieldingChainsaw) {
if (mainHandItem.is(CustomBlocks.ITEM_CHAINSAW.get()) || offHandItem.is(CustomBlocks.ITEM_CHAINSAW.get())) {
this.isWieldingChainsaw = true;
this.chainsawStartTick = ModernLifeCommon.clientTickCounter;
}
} else {
int tickDiff = ModernLifeCommon.clientTickCounter - this.chainsawStartTick;
if (!mainHandItem.is(CustomBlocks.ITEM_CHAINSAW.get()) && !offHandItem.is(CustomBlocks.ITEM_CHAINSAW.get())) {
if (this.isWieldingChainsaw && tickDiff >= 18) {
chainsawStopSound(level, localPlayer, 0);
}
this.isWieldingChainsaw = false;
} else if (tickDiff == 6) {
chainsawStartSound(level, localPlayer, 0);
} else if (tickDiff >= 18 && (le.getUseItem() == null || !le.getUseItem().is(CustomBlocks.ITEM_CHAINSAW.get()))) {
chainsawIdleSound(level, localPlayer, ModernLifeCommon.clientTickCounter);
}
}
}
}
super.inventoryTick(itemStack, level, entity, slot, isMainHand);
}
public void onUsingTick(ItemStack itemStack, LivingEntity livingEntity, int count) {
if (livingEntity instanceof Player) {
Player player = (Player) livingEntity;
if (livingEntity.level.isClientSide) {
if (livingEntity != Minecraft.getInstance().player) {
return;
}
EntityHitResult rayTraceForPlayer = getRayTraceForPlayer(player.level, player);
BlockHitResult blockRayTrace = null;
int entityId = -1;
if (rayTraceForPlayer.getType() == HitResult.Type.ENTITY) {
EntityHitResult entityRayTrace = rayTraceForPlayer;
Entity entity = entityRayTrace.getEntity();
if (entity instanceof LivingEntity) {
entityId = entity.getId();
Vec3 loc = entityRayTrace.getLocation();
blockRayTrace = BlockHitResult.miss(loc, Direction.UP, new BlockPos(loc.x, loc.y, loc.z));
}
} else if (rayTraceForPlayer.getType() == HitResult.Type.BLOCK) {
blockRayTrace = (BlockHitResult) rayTraceForPlayer;
}
float pitchMod = 0.0f;
if (rayTraceForPlayer.getType() == HitResult.Type.BLOCK || rayTraceForPlayer.getType() == HitResult.Type.ENTITY) {
pitchMod = 0.1f;
}
chainsawSound(player.level, player, count, pitchMod);
ServerboundChainsawTargetPacket chainsawTarget = new ServerboundChainsawTargetPacket(blockRayTrace, entityId);
ModernLifeNetwork.INSTANCE.sendToServer(chainsawTarget);
return;
}
MiningInfo mInfo = mineMap.get(player);
if (mInfo == null) {
mInfo = new MiningInfo();
mineMap.put(player, mInfo);
}
ServerLevel serverLevel = livingEntity.level;
EntityHitResult entityRayTrace2 = mInfo.rayTrace;
if (entityRayTrace2 == null) {
return;
}
float pitchMod2 = 0.0f;
if (entityRayTrace2.getType() == HitResult.Type.BLOCK || entityRayTrace2.getType() == HitResult.Type.ENTITY) {
pitchMod2 = 0.1f;
}
chainsawSound(player.level, player, count, pitchMod2);
Vec3 loc2 = entityRayTrace2.getLocation();
if (entityRayTrace2.getType() == HitResult.Type.ENTITY) {
mInfo.rayTrace = entityRayTrace2;
Entity entity2 = entityRayTrace2.getEntity();
if ((entity2 instanceof LivingEntity) && itemStack != null && itemStack.getItem() == CustomBlocks.ITEM_CHAINSAW.get() && itemStack.getCount() > 0) {
chainsawAttack(serverLevel, player, itemStack, entity2, loc2);
if (!entity2.isAlive()) {
mInfo.rayTrace = null;
return;
}
return;
}
return;
}
if (entityRayTrace2.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockRayTrace2 = (BlockHitResult) entityRayTrace2;
double pickRange = player.getAttribute(ForgeMod.REACH_DISTANCE.get()).getValue();
double chainsawRange = pickRange * 1.0d;
double chainsawRangeSqr = chainsawRange * chainsawRange;
if (blockRayTrace2.getLocation().distanceToSqr(player.getEyePosition(1.0f)) > chainsawRangeSqr) {
return;
}
BlockPos pos = blockRayTrace2.getBlockPos();
BlockState state = serverLevel.getBlockState(pos);
if (!state.isAir()) {
ParticleType particles = ForgeRegistries.PARTICLE_TYPES.getValue(ForgeRegistries.PARTICLE_TYPES.getKey(ParticleTypes.BLOCK));
if (particles != null) {
BlockParticleOption blockParticle = new BlockParticleOption(particles, state);
if (serverLevel instanceof ServerLevel) {
for (int i = 0; i < 10; i++) {
serverLevel.sendParticles(blockParticle, loc2.x + ((Math.random() * 1.0d) - 0.5d), loc2.y + ((Math.random() * 1.0d) - 0.5d), loc2.z + ((Math.random() * 1.0d) - 0.5d), 1, 0.0d, 0.0d, 0.0d, 0.0d);
}
}
}
mineIfPossible(player, serverLevel, pos, mInfo);
}
}
}
}
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
return false;
}
public void destroyGrid(Level world, BlockPos center, int width, int height) {
BlockPos newCenter = center.below(height / 2);
for (int h = 0; h < height; h++) {
BlockPos westPos = newCenter.west(width / 2);
for (int w = 0; w < width; w++) {
BlockPos destroyPos = westPos.north(width / 2);
for (int slice = 0; slice < width; slice++) {
if (!destroyPos.equals(center) && world.getBlockState(destroyPos).is(world.getBlockState(center).getBlock())) {
destroyIfPossible(world, destroyPos);
}
destroyPos = destroyPos.south();
}
westPos = westPos.east();
}
newCenter = newCenter.above();
}
}
public boolean mineIfPossible(Player player, Level world, BlockPos pos, MiningInfo mInfo) {
if (!pos.equals(mInfo.pos)) {
mInfo.pos = pos;
mInfo.miningProgress = 0.0f;
return false;
}
BlockState state = world.getBlockState(pos);
float toolMult = getDestroySpeed(player.getUseItem(), state);
float usingChainsawMult = 2.0f;
ItemStack itemStack = player.getUseItem();
float enchantMult = 1.0f;
if (CHAINSAW_MATERIALS.contains(state.m_60767_()) || CHAINSAW_BLOCKS.contains(state.getBlock())) {
usingChainsawMult = 6.0f;
if (itemStack.isEnchanted()) {
ListTag enchantmentTags = itemStack.getEnchantmentTags();
for (int i = 0; i < enchantmentTags.size(); i++) {
CompoundTag compoundTag = enchantmentTags.get(i);
if (compoundTag instanceof CompoundTag) {
CompoundTag nbt = compoundTag;
String id = nbt.getString("id");
int level = nbt.getInt("lvl");
if (id != null && "minecraft:efficiency".equals(id) && level > 0) {
enchantMult = 1.0f + (level / 5.0f);
}
}
}
}
}
float blockDestroySpeed = state.m_60800_(world, pos);
float progressIncrement = ((usingChainsawMult * toolMult) * enchantMult) / blockDestroySpeed;
mInfo.miningProgress += progressIncrement;
state.m_60625_(player, world, pos);
int newProgressValueToSet = (int) (mInfo.miningProgress / 10.0f);
world.destroyBlockProgress(-1, pos, newProgressValueToSet - 1);
if (mInfo.miningProgress >= 100.0f && (world instanceof ServerLevel)) {
mInfo.pos = null;
mInfo.miningProgress = 0.0f;
if (CHAINSAW_MATERIALS.contains(state.m_60767_()) || CHAINSAW_BLOCKS.contains(state.getBlock())) {
destroyGrid(world, pos, 3, 3);
if (state.m_60767_() != Material.LEAVES) {
itemStack.hurtAndBreak(3, player, x -> {
});
}
} else {
itemStack.hurtAndBreak(6, player, x2 -> {
});
}
world.destroyBlockProgress(player.getId(), pos, 10);
return world.m_46961_(pos, true);
}
return false;
}
public boolean destroyIfPossible(Level world, BlockPos pos) {
BlockState state = world.getBlockState(pos);
if (CHAINSAW_MATERIALS.contains(state.m_60767_()) || CHAINSAW_BLOCKS.contains(state.getBlock())) {
return world.m_46961_(pos, true);
}
return false;
}
private HitResult getRayTraceForPlayer(Level world, Player player) {
double d0;
double d02 = Minecraft.getInstance().gameMode.getPickRange();
HitResult rayTrace = Item.getPlayerPOVHitResult(world, player, ClipContext.Fluid.NONE);
Vec3 Vec3 = player.getEyePosition(1.0f);
boolean flag = false;
double d1 = d02;
if (Minecraft.getInstance().gameMode.hasFarPickRange()) {
d1 = 6.0d;
d0 = 6.0d;
} else {
if (d02 > 3.0d) {
flag = true;
}
d0 = d02;
}
double d12 = d1 * d1;
if (rayTrace != null) {
d12 = rayTrace.getLocation().distanceToSqr(Vec3);
}
Vec3 Vec31 = player.getViewVector(1.0f);
Vec3 Vec32 = Vec3.add(Vec31.x * d0, Vec31.y * d0, Vec31.z * d0);
AABB axisalignedbb = player.getBoundingBox().expandTowards(Vec31.scale(d0)).inflate(1.0d, 1.0d, 1.0d);
HitResult entityHitResult = ProjectileUtil.getEntityHitResult(player, Vec3, Vec32, axisalignedbb, entity -> {
return !entity.isSpectator() && entity.isPickable();
}, d12);
if (entityHitResult != null) {
entityHitResult.getEntity();
Vec3 Vec33 = entityHitResult.getLocation();
double d2 = Vec3.distanceToSqr(Vec33);
if (flag && d2 > 9.0d) {
rayTrace = BlockHitResult.miss(Vec33, Direction.getNearest(Vec31.x, Vec31.y, Vec31.z), new BlockPos(Vec33));
} else if (d2 < d12 || rayTrace == null) {
rayTrace = entityHitResult;
}
}
return rayTrace;
}
public void appendHoverText(ItemStack itemStack, @Nullable Level world, List<Component> text, TooltipFlag flag) {
text.add(new TextComponent("Right click to use"));
text.add(new TextComponent("* Highly effective on trees and leaves"));
}
public void releaseUsing(ItemStack itemStack, Level p_77615_2_, LivingEntity entity, int p_77615_4_) {
if (entity instanceof Player) {
Player player = (Player) entity;
player.stopUsingItem();
MiningInfo mInfo = mineMap.get(player);
if (mInfo != null) {
mInfo.pos = null;
}
}
}
public int getUseDuration(ItemStack stack) {
return 72000;
}
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand p_77659_3_) {
ItemStack itemStack = player.getItemInHand(p_77659_3_);
player.startUsingItem(p_77659_3_);
return InteractionResultHolder.consume(itemStack);
}
}