Smashing! Although I think the break code is duping sounds

This commit is contained in:
Michael Hillcox 2020-12-06 18:32:20 +00:00
parent a94af5e247
commit 4f33a9fb2d
No known key found for this signature in database
GPG key ID: 971C5B254742488F
5 changed files with 276 additions and 24 deletions

View file

@ -1,5 +1,10 @@
package de.ellpeck.actuallyadditions.common.config;
import com.google.common.collect.ImmutableList;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import java.util.List;
import static de.ellpeck.actuallyadditions.common.config.Config.COMMON_BUILDER;
import static net.minecraftforge.common.ForgeConfigSpec.IntValue;
@ -7,6 +12,7 @@ public class ItemConfig {
public final IntValue teleportStaffCost;
public final IntValue teleportStaffMaxEnergy;
public final IntValue drillMaxEnergy;
public final ConfigValue<List<String>> drillSpecialBlockWhitelist;
public ItemConfig() {
COMMON_BUILDER.comment("Item Config Options").push("items");
@ -25,5 +31,9 @@ public class ItemConfig {
drillMaxEnergy = COMMON_BUILDER
.comment("The max energy amount for the drill")
.defineInRange("Drill Max Energy", 250000, 0, 1000000);
drillSpecialBlockWhitelist = COMMON_BUILDER
.comment("By default, the Drill can mine certain blocks. If there is one that it can't mine, but should be able to, put its REGISTRY NAME here. These are the actual registered Item Names, the ones you use, for example, when using the /give Command.")
.define("Drill special block whitelist", ImmutableList.of("examplemod:block_one"));
}
}

View file

@ -17,7 +17,14 @@ import net.minecraftforge.items.wrapper.InvWrapper;
import javax.annotation.Nonnull;
public class DrillContainer extends Container {
private final ItemStackHandler handler;
public static final int AUGMENT_SLOT_COUNT = 3;
private final ItemStackHandler handler = new ItemStackHandler(AUGMENT_SLOT_COUNT) {
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
return stack.getItem() instanceof DrillAugmentItem;
}
};
private final PlayerInventory inv;
private final ItemStack stack;
@ -34,15 +41,7 @@ public class DrillContainer extends Container {
ContainerHelper.setupPlayerInventory(new InvWrapper(inv), 0, ContainerHelper.DEFAULT_SLOTS_X, 116, this::addSlot);
this.handler = new ItemStackHandler(5) {
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
return stack.getItem() instanceof DrillAugmentItem;
}
};
this.handler.deserializeNBT(this.stack.getOrCreateChildTag("augments"));
this.handler.deserializeNBT(this.stack.getOrCreateChildTag(DrillItem.NBT_AUGMENT_TAG));
this.addContainerSlots();
}
@ -53,7 +52,7 @@ public class DrillContainer extends Container {
}
protected void addContainerSlots() {
for (int i = 0; i < 5; i ++) {
for (int i = 0; i < AUGMENT_SLOT_COUNT; i ++) {
addSlot(new SlotItemHandler(handler, i, 44 + (i * ContainerHelper.SLOT_SPACING), 19));
}
}
@ -89,7 +88,7 @@ public class DrillContainer extends Container {
}
} else {
// Moves the item from the players inventory to the drill
if (!this.mergeItemStack(fromStack, ContainerHelper.PLAYER_INVENTORY_END_SLOT + 1, ContainerHelper.PLAYER_INVENTORY_END_SLOT + 6, false)) {
if (!this.mergeItemStack(fromStack, ContainerHelper.PLAYER_INVENTORY_END_SLOT + 1, ContainerHelper.PLAYER_INVENTORY_END_SLOT + (AUGMENT_SLOT_COUNT + 1), false)) {
return ItemStack.EMPTY;
}
}
@ -101,6 +100,6 @@ public class DrillContainer extends Container {
public void onContainerClosed(@Nonnull PlayerEntity playerIn) {
super.onContainerClosed(playerIn);
this.stack.getOrCreateTag().put("augments", this.handler.serializeNBT());
this.stack.getOrCreateTag().put(DrillItem.NBT_AUGMENT_TAG, this.handler.serializeNBT());
}
}

View file

@ -20,6 +20,7 @@ import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
@ -72,7 +73,7 @@ public abstract class CrystalFluxItem extends ActuallyItem {
public void addInformation(ItemStack stack, @Nullable World worldIn, List<ITextComponent> tooltip, ITooltipFlag flagIn) {
super.addInformation(stack, worldIn, tooltip, flagIn);
stack.getCapability(CapabilityEnergy.ENERGY).ifPresent(energy ->
getCrystalFlux(stack).ifPresent(energy ->
tooltip.add(this.getEnergyPretty(energy, Screen.hasShiftDown()).mergeStyle(TextFormatting.GRAY)));
}
@ -120,8 +121,12 @@ public abstract class CrystalFluxItem extends ActuallyItem {
@Override
public double getDurabilityForDisplay(ItemStack stack) {
return stack.getCapability(CapabilityEnergy.ENERGY)
return getCrystalFlux(stack)
.map(energy -> 1D - (energy.getEnergyStored() / (double) energy.getMaxEnergyStored()))
.orElse(0D);
}
public LazyOptional<IEnergyStorage> getCrystalFlux(ItemStack stack) {
return stack.getCapability(CapabilityEnergy.ENERGY);
}
}

View file

@ -15,14 +15,24 @@ public class DrillAugmentItem extends ActuallyItem {
}
public enum AugmentType {
SPEED_AUGMENT_I,
SPEED_AUGMENT_II,
SPEED_AUGMENT_III,
SILK_TOUCH_AUGMENT,
FORTUNE_AUGMENT_I,
FORTUNE_AUGMENT_II,
MINING_AUGMENT_I,
MINING_AUGMENT_II,
BLOCK_PLACING_AUGMENT
SPEED_AUGMENT_I(50),
SPEED_AUGMENT_II(75),
SPEED_AUGMENT_III(175),
SILK_TOUCH_AUGMENT(100),
FORTUNE_AUGMENT_I(40),
FORTUNE_AUGMENT_II(80),
MINING_AUGMENT_I(10),
MINING_AUGMENT_II(30),
BLOCK_PLACING_AUGMENT(0);
int energyCost;
AugmentType(int energyCost) {
this.energyCost = energyCost;
}
public int getEnergyCost() {
return energyCost;
}
}
}

View file

@ -1,20 +1,52 @@
package de.ellpeck.actuallyadditions.common.items.useables;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import de.ellpeck.actuallyadditions.common.config.Config;
import de.ellpeck.actuallyadditions.common.container.DrillContainer;
import de.ellpeck.actuallyadditions.common.items.CrystalFluxItem;
import de.ellpeck.actuallyadditions.common.items.misc.DrillAugmentItem;
import de.ellpeck.actuallyadditions.common.utilities.Help;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.ai.attributes.Attribute;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.inventory.container.SimpleNamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.items.ItemStackHandler;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import static de.ellpeck.actuallyadditions.common.items.misc.DrillAugmentItem.AugmentType;
public class DrillItem extends CrystalFluxItem {
public static final String NBT_AUGMENT_TAG = "augments";
private static final int BASE_ENERGY_USE = 100;
public DrillItem() {
super(
baseProps()
@ -27,6 +59,117 @@ public class DrillItem extends CrystalFluxItem {
);
}
@Override
public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlotType equipmentSlot, ItemStack stack) {
Multimap<Attribute, AttributeModifier> map = HashMultimap.create();
if (equipmentSlot == EquipmentSlotType.MAINHAND) {
map.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Drill Modifier", getCrystalFlux(stack).map(IEnergyStorage::getEnergyStored).orElse(0) >= BASE_ENERGY_USE ? 8.0F : 0.1F, AttributeModifier.Operation.ADDITION));
map.put(Attributes.ATTACK_SPEED, new AttributeModifier(ATTACK_SPEED_MODIFIER, "Tool Modifier", -2.5F, AttributeModifier.Operation.ADDITION));
}
return map;
}
@Override
public boolean onBlockStartBreak(ItemStack stack, BlockPos posIn, PlayerEntity player) {
int crystalFlux = getCrystalFlux(stack).map(IEnergyStorage::getEnergyStored).orElse(0);
int fluxPerBlock = this.getFluxPerBlock(stack);
if (crystalFlux < fluxPerBlock) {
return false;
}
ImmutableSet<AugmentType> augments = getAugments(stack);
ItemStack drill = stack.copy(); // copy to apply enchants
// Apply enchants
if (hasAugment(augments, AugmentType.SILK_TOUCH_AUGMENT)) {
drill.addEnchantment(Enchantments.SILK_TOUCH, 1);
}
if (hasAugment(augments, AugmentType.FORTUNE_AUGMENT_I) || hasAugment(augments, AugmentType.FORTUNE_AUGMENT_II)) {
drill.addEnchantment(Enchantments.FORTUNE, hasAugment(augments, AugmentType.FORTUNE_AUGMENT_I) ? 1 : 3);
}
if ((hasAugment(augments, AugmentType.MINING_AUGMENT_I) || hasAugment(augments, AugmentType.MINING_AUGMENT_II))) {
return this.breakBlocksWithAoe(player, player.world, stack, drill, fluxPerBlock, hasAugment(augments, AugmentType.MINING_AUGMENT_I) ? 1 : 2);
} else {
return this.destroyBlock(posIn, player, player.world, stack, drill, fluxPerBlock);
}
}
private boolean breakBlocksWithAoe(PlayerEntity player, World world, ItemStack drill, ItemStack drillEnchanted, int fluxPerBlock, int radius) {
double distance = Objects.requireNonNull(player.getAttribute(ForgeMod.REACH_DISTANCE.get())).getValue();
RayTraceResult trace = player.pick(player.isCreative() ? distance : distance - 0.5D, 1F, false);
if (trace.getType() != RayTraceResult.Type.BLOCK) {
return false;
}
BlockRayTraceResult pick = (BlockRayTraceResult) trace;
BlockPos pos = pick.getPos();
Direction.Axis axis = pick.getFace().getAxis();
Set<BlockPos> posSet = new HashSet<>();
// Uses the facing axis to move around the X,Y,Z to allow for multiple faces in 2 for loops
int a = axis != Direction.Axis.X ? pos.getX() : pos.getY(); // Z & Y plane both use X
int b = axis != Direction.Axis.Z ? pos.getZ() : pos.getY(); // X & Y plane both use Z
for (int i = (a - radius); i < (a + radius) + 1; i++) {
for (int j = (b - radius); j < (b + radius) + 1; j++) {
// Assign [a] and [b] to X, Y, or Z depending on the axis
posSet.add(new BlockPos(
axis != Direction.Axis.X ? i : pos.getX(),
axis == Direction.Axis.X ? i : (axis == Direction.Axis.Z ? j : pos.getY()),
axis != Direction.Axis.Z ? j : pos.getZ()
));
}
}
Set<BlockPos> failed = new HashSet<>();
posSet.forEach(e -> {
if (!destroyBlock(e, player, world, drill, drillEnchanted, fluxPerBlock)) {
failed.add(e);
}
});
return failed.contains(pick.getPos());
}
private boolean destroyBlock(BlockPos pos, PlayerEntity player, World world, ItemStack drill, ItemStack drillEnchanted, int fluxPerBlock) {
BlockState state = world.getBlockState(pos);
int flux = this.getCrystalFlux(drill).map(IEnergyStorage::getEnergyStored).orElse(0);
if (!ForgeHooks.canHarvestBlock(state, player, world, pos) || flux < fluxPerBlock) {
return false;
}
if (!world.isRemote) {
int event = ForgeHooks.onBlockBreakEvent(world, ((ServerPlayerEntity) player).interactionManager.getGameType(), (ServerPlayerEntity) player, pos);
if (event == -1) {
return false;
}
TileEntity tileEntity = world.getTileEntity(pos);
state.getBlock().onPlayerDestroy(world, pos, state);
state.getBlock().harvestBlock(world, player, pos, state, tileEntity, drillEnchanted);
state.getBlock().dropXpOnBlockBreak((ServerWorld) world, pos, event);
}
// Old Ell Code :cry:, I mean, it's perfect!
// Client code
world.playEvent(2001, pos, Block.getStateId(state));
if (state.getBlock().removedByPlayer(state, world, pos, player, true, world.getFluidState(pos))) {
state.getBlock().onPlayerDestroy(world, pos, state);
}
// callback to the tool
drill.onBlockDestroyed(world, state, pos, player);
return true;
}
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity player, Hand handIn) {
ItemStack stack = player.getHeldItem(handIn);
@ -43,4 +186,89 @@ public class DrillItem extends CrystalFluxItem {
return ActionResult.resultSuccess(stack);
}
@Override
public float getDestroySpeed(ItemStack stack, BlockState state) {
int flux = getCrystalFlux(stack).map(IEnergyStorage::getEnergyStored).orElse(0);
if (flux == 0 || flux <= this.getFluxPerBlock(stack))
return 0.1f;
return blockIsPartOfSpecialWhitelist(state) || state.getHarvestTool() == null || this.getToolTypes(stack).contains(state.getHarvestTool())
? this.getDestroySpeedFromUpgrades(stack)
: 1.0f;
}
/**
* Calculates the speed the drill can mine based on it's augments and it's reducer augments
*
* @return speed that the drill can mine
*/
private float getDestroySpeedFromUpgrades(ItemStack stack) {
float speed = 8.0f;
ImmutableSet<AugmentType> augments = getAugments(stack);
if (augments.size() == 0) {
return speed;
}
float reduction = hasAugment(augments, AugmentType.MINING_AUGMENT_I) ? (hasAugment(augments, AugmentType.MINING_AUGMENT_II) ? 0.5f : 0.35f) : 1f;
float modifier = hasAugment(augments, AugmentType.SPEED_AUGMENT_I)
? 8.0f
: (hasAugment(augments, AugmentType.SPEED_AUGMENT_II)
? 25.0f
: (hasAugment(augments, AugmentType.SPEED_AUGMENT_III) ? 37.0f : 0f));
return (speed + modifier) * reduction;
}
/**
* Calculates the cost to mine a block based on the items augments
*
* @return the cost per operation
*/
private int getFluxPerBlock(ItemStack stack) {
return BASE_ENERGY_USE + getAugments(stack).stream().mapToInt(AugmentType::getEnergyCost).sum();
}
/**
* Checks whether or not a state can be mined even if the other operators fail
*/
private boolean blockIsPartOfSpecialWhitelist(BlockState state) {
ResourceLocation location = state.getBlock().getRegistryName();
if (location == null) {
return false;
}
return Config.ITEM_CONFIG.drillSpecialBlockWhitelist.get().contains(location.toString());
}
private boolean hasAugment(ItemStack stack, AugmentType type) {
return getAugments(stack).contains(type);
}
/**
* Use this in preference for {@link #hasAugment(ItemStack, AugmentType)} when doing multiple comparisons
*/
private boolean hasAugment(ImmutableSet<AugmentType> augments, AugmentType type) {
return augments.contains(type);
}
/**
* Returns a list of AugmentTypes attached to the item stack.
*/
private ImmutableSet<AugmentType> getAugments(ItemStack stack) {
ItemStackHandler handler = new ItemStackHandler();
handler.deserializeNBT(stack.getOrCreateChildTag(NBT_AUGMENT_TAG));
ImmutableSet.Builder<AugmentType> augments = ImmutableSet.builder();
for (int i = 0; i < handler.getSlots(); i ++) {
ItemStack stackInSlot = handler.getStackInSlot(i);
if (!stackInSlot.isEmpty() && stackInSlot.getItem() instanceof DrillAugmentItem) {
augments.add(((DrillAugmentItem) stackInSlot.getItem()).getType());
}
}
return augments.build();
}
}