Add Annihilation Plane enchantment support, deprecate Identity (#510)
This commit is contained in:
@@ -48,25 +48,39 @@ import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.MachineSource;
|
||||
import appeng.parts.PartBasicState;
|
||||
import appeng.util.EnchantmentUtil;
|
||||
import appeng.util.IWorldCallable;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.SettingsFrom;
|
||||
import appeng.util.item.AEItemStack;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Enchantments;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.common.util.FakePlayerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
|
||||
public class PartAnnihilationPlane extends PartBasicState implements IGridTickable, IWorldCallable<TickRateModulation> {
|
||||
@@ -82,6 +96,12 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
private boolean isAccepting = true;
|
||||
private boolean breaking = false;
|
||||
|
||||
/**
|
||||
* Enchantments found on the plane when it was placed will be used to enchant the fake tool used for picking up
|
||||
* blocks.
|
||||
*/
|
||||
private Map<Enchantment, Integer> enchantments = new LinkedHashMap<>();
|
||||
|
||||
public PartAnnihilationPlane(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
@@ -92,6 +112,7 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
return this.breakBlock(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
int minX = 1;
|
||||
@@ -422,14 +443,38 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
}
|
||||
|
||||
protected List<ItemStack> obtainBlockDrops(final WorldServer w, final BlockPos pos) {
|
||||
final ItemStack[] out = Platform.getBlockDrops(w, pos);
|
||||
return Lists.newArrayList(out);
|
||||
final FakePlayer fakePlayer = FakePlayerFactory.getMinecraft(w);
|
||||
final IBlockState state = w.getBlockState(pos);
|
||||
|
||||
if (state.getBlock().canSilkHarvest(w, pos, state, fakePlayer) && enchantments.containsKey(Enchantments.SILK_TOUCH)) {
|
||||
final List<ItemStack> out = new ArrayList<>(1);
|
||||
final Item item = Item.getItemFromBlock(state.getBlock());
|
||||
|
||||
if (item != Items.AIR) {
|
||||
int meta = 0;
|
||||
if (item.getHasSubtypes()) {
|
||||
meta = state.getBlock().getMetaFromState(state);
|
||||
}
|
||||
final ItemStack itemstack = new ItemStack(item, 1, meta);
|
||||
out.add(itemstack);
|
||||
}
|
||||
return out;
|
||||
} else {
|
||||
if (enchantments.containsKey(Enchantments.FORTUNE)) {
|
||||
final ItemStack[] out = Platform.getBlockDrops(w, pos, enchantments.get(Enchantments.FORTUNE));
|
||||
return Lists.newArrayList(out);
|
||||
} else {
|
||||
ItemStack[] blockDrops = Platform.getBlockDrops(w, pos);
|
||||
return Lists.newArrayList(blockDrops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this plane can handle the block at the specific coordinates.
|
||||
*/
|
||||
protected float calculateEnergyUsage(final WorldServer w, final BlockPos pos, final List<ItemStack> items) {
|
||||
boolean useEnergy = true;
|
||||
final IBlockState state = w.getBlockState(pos);
|
||||
final float hardness = state.getBlockHardness(w, pos);
|
||||
|
||||
@@ -438,7 +483,25 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
requiredEnergy += is.getCount();
|
||||
}
|
||||
|
||||
return requiredEnergy;
|
||||
if (!enchantments.isEmpty()) {
|
||||
var efficiencyFactor = 1f;
|
||||
var efficiencyLevel = 0;
|
||||
if (enchantments.containsKey(Enchantments.EFFICIENCY)) {
|
||||
// Reduce total energy usage incurred by other enchantments by 15% per Efficiency level.
|
||||
efficiencyLevel = enchantments.get(Enchantments.EFFICIENCY);
|
||||
efficiencyFactor *= Math.pow(0.85, efficiencyLevel);
|
||||
}
|
||||
if (enchantments.containsKey(Enchantments.UNBREAKING)) {
|
||||
// Give plane only a (100 / (level + 1))% chance to use energy.
|
||||
// This is similar to vanilla Unbreaking behaviour for tools.
|
||||
int randomNumber = ThreadLocalRandom.current().nextInt(enchantments.get(Enchantments.UNBREAKING) + 1);
|
||||
useEnergy = randomNumber == 0;
|
||||
}
|
||||
var levelSum = enchantments.values().stream().reduce(0, Integer::sum) - efficiencyLevel;
|
||||
requiredEnergy *= 8 * levelSum * efficiencyFactor;
|
||||
}
|
||||
|
||||
return useEnergy ? requiredEnergy : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,10 +510,10 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
* It also sets isAccepting to false, if the item can not be stored.
|
||||
*
|
||||
* @param itemStacks an array of {@link ItemStack} to test
|
||||
* @return true, if the network can store at least a single item of all drops or no drops are reported
|
||||
* @return true, if the network can store all drops or no drops are reported
|
||||
*/
|
||||
private boolean canStoreItemStacks(final List<ItemStack> itemStacks) {
|
||||
boolean canStore = itemStacks.isEmpty();
|
||||
boolean canStore = true;
|
||||
|
||||
try {
|
||||
final IStorageGrid storage = this.getProxy().getStorage();
|
||||
@@ -459,8 +522,8 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
final IAEItemStack itemToTest = AEItemStack.fromItemStack(itemStack);
|
||||
final IAEItemStack overflow = storage.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
|
||||
.injectItems(itemToTest, Actionable.SIMULATE, this.mySrc);
|
||||
if (overflow == null || itemToTest.getStackSize() > overflow.getStackSize()) {
|
||||
canStore = true;
|
||||
if (overflow != null) {
|
||||
canStore = false;
|
||||
}
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
@@ -472,15 +535,20 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
}
|
||||
|
||||
private void breakBlockAndStoreItems(final WorldServer w, final BlockPos pos) {
|
||||
w.destroyBlock(pos, true);
|
||||
final List<ItemStack> items = this.obtainBlockDrops(w, pos);
|
||||
|
||||
final AxisAlignedBB box = new AxisAlignedBB(pos).grow(0.2);
|
||||
for (final Object ei : w.getEntitiesWithinAABB(EntityItem.class, box)) {
|
||||
if (ei instanceof EntityItem) {
|
||||
final EntityItem entityItem = (EntityItem) ei;
|
||||
this.storeEntityItem(entityItem);
|
||||
try {
|
||||
final IStorageGrid storage = this.getProxy().getStorage();
|
||||
for (ItemStack itemStack : items) {
|
||||
final IAEItemStack aeItemStack = AEItemStack.fromItemStack(itemStack);
|
||||
storage.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class))
|
||||
.injectItems(aeItemStack, Actionable.MODULATE, this.mySrc);
|
||||
}
|
||||
} catch (GridAccessException e) {
|
||||
|
||||
}
|
||||
|
||||
w.destroyBlock(pos, false);
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
@@ -498,4 +566,50 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
|
||||
return MODELS.getModel(this.getConnections(), this.isPowered(), this.isActive());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NBTTagCompound downloadSettings(SettingsFrom from, NBTTagCompound output) {
|
||||
super.downloadSettings(from, output);
|
||||
// Save enchants only when the actual plane is dismantled
|
||||
if (from == SettingsFrom.DISMANTLE_ITEM) {
|
||||
writeEnchantments(output);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadSettings(SettingsFrom from, NBTTagCompound output, EntityPlayer player) {
|
||||
super.uploadSettings(from, output, player);
|
||||
// Import enchants only when the plan is placed, not from memory cards
|
||||
if (from == SettingsFrom.DISMANTLE_ITEM) {
|
||||
readEnchantments(output);
|
||||
}
|
||||
}
|
||||
|
||||
public void readEnchantments(NBTTagCompound data) {
|
||||
enchantments = EnchantmentUtil.getEnchantments(data);
|
||||
EnchantmentHelper.setEnchantments(enchantments, getItemStack());
|
||||
}
|
||||
|
||||
public void writeEnchantments(NBTTagCompound data) {
|
||||
EnchantmentUtil.setEnchantments(data, enchantments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound data) {
|
||||
super.readFromNBT(data);
|
||||
readEnchantments(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound data) {
|
||||
super.writeToNBT(data);
|
||||
writeEnchantments(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToWorld() {
|
||||
super.addToWorld();
|
||||
enchantments = EnchantmentHelper.getEnchantments(getItemStack());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user