diff --git a/src/main/java/gregtech/api/capability/ConfigurationContext.java b/src/main/java/gregtech/api/capability/ConfigurationContext.java new file mode 100755 index 0000000000..76410c5075 --- /dev/null +++ b/src/main/java/gregtech/api/capability/ConfigurationContext.java @@ -0,0 +1,24 @@ +package gregtech.api.capability; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; + +/** + * Context used during configuration events + */ +public interface ConfigurationContext extends ICapabilityProvider { + + default boolean isAdvanced() { + return false; + } + + // For feedback + void sendMessage(ITextComponent component); + + @Override + default boolean hasCapability(final Capability capability, final EnumFacing facing) { + return getCapability(capability, facing) != null; + } +} \ No newline at end of file diff --git a/src/main/java/gregtech/api/capability/GregtechCapabilities.java b/src/main/java/gregtech/api/capability/GregtechCapabilities.java index 7e9d215470..eef2a497cb 100644 --- a/src/main/java/gregtech/api/capability/GregtechCapabilities.java +++ b/src/main/java/gregtech/api/capability/GregtechCapabilities.java @@ -1,5 +1,6 @@ package gregtech.api.capability; +import gregtech.api.capability.tool.IConfiguratorItem; import gregtech.api.capability.tool.IScrewdriverItem; import gregtech.api.capability.tool.ISoftHammerItem; import gregtech.api.capability.tool.IWrenchItem; @@ -23,6 +24,9 @@ public class GregtechCapabilities { @CapabilityInject(ISoftHammerItem.class) public static Capability CAPABILITY_MALLET = null; + @CapabilityInject(IConfiguratorItem.class) + public static Capability CAPABILITY_CONFIGURATOR = null; + @CapabilityInject(IFuelable.class) public static Capability CAPABILITY_FUELABLE = null; diff --git a/src/main/java/gregtech/api/capability/GregtechTileCapabilities.java b/src/main/java/gregtech/api/capability/GregtechTileCapabilities.java index 410e13b5a8..700b597f41 100644 --- a/src/main/java/gregtech/api/capability/GregtechTileCapabilities.java +++ b/src/main/java/gregtech/api/capability/GregtechTileCapabilities.java @@ -18,4 +18,6 @@ public class GregtechTileCapabilities { @CapabilityInject(IActiveOutputSide.class) public static Capability CAPABILITY_ACTIVE_OUTPUT_SIDE = null; + @CapabilityInject(IConfigurable.class) + public static Capability CAPABILITY_CONFIGURABLE = null; } diff --git a/src/main/java/gregtech/api/capability/IConfigurable.java b/src/main/java/gregtech/api/capability/IConfigurable.java new file mode 100755 index 0000000000..bcd16ea0a5 --- /dev/null +++ b/src/main/java/gregtech/api/capability/IConfigurable.java @@ -0,0 +1,18 @@ +package gregtech.api.capability; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; + +/** + * For configurable things + */ +public interface IConfigurable { + + ResourceLocation getConfigurationID(); + + String getConfigurationName(); + + NBTTagCompound copyConfiguration(ConfigurationContext context); + + void pasteConfiguration(ConfigurationContext context, NBTTagCompound configuration); +} \ No newline at end of file diff --git a/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java b/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java index 42c545c200..04cac606aa 100644 --- a/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java +++ b/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java @@ -1,5 +1,6 @@ package gregtech.api.capability; +import gregtech.api.capability.tool.IConfiguratorItem; import gregtech.api.capability.tool.IScrewdriverItem; import gregtech.api.capability.tool.ISoftHammerItem; import gregtech.api.capability.tool.IWrenchItem; @@ -40,10 +41,12 @@ public static void init() { registerCapabilityWithNoDefault(IControllable.class); registerCapabilityWithNoDefault(IActiveOutputSide.class); registerCapabilityWithNoDefault(IFuelable.class); + registerCapabilityWithNoDefault(IConfigurable.class); registerCapabilityWithNoDefault(IWrenchItem.class); registerCapabilityWithNoDefault(IScrewdriverItem.class); registerCapabilityWithNoDefault(ISoftHammerItem.class); + registerCapabilityWithNoDefault(IConfiguratorItem.class); //internal capabilities CapabilityManager.INSTANCE.register(GTWorldGenCapability.class, GTWorldGenCapability.STORAGE, GTWorldGenCapability.FACTORY); diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java index 6b92342620..f2eccdd342 100755 --- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java +++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java @@ -1,6 +1,7 @@ package gregtech.api.capability.impl; import gregtech.api.GTValues; +import gregtech.api.capability.ConfigurationContext; import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IMultipleTankHandler; import gregtech.api.capability.IWorkable; @@ -504,4 +505,30 @@ public void deserializeNBT(NBTTagCompound compound) { } } + @Override + protected boolean isConfigurable() { + return true; + } + + @Override + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + final NBTTagCompound compound = super.copyConfiguration(context); + compound.setBoolean(ALLOW_OVERCLOCKING, this.allowOverclocking); + compound.setLong(OVERCLOCK_VOLTAGE, this.overclockVoltage); + return compound; + } + + @Override + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound compound) { + super.pasteConfiguration(context, compound); + if (compound.hasKey(ALLOW_OVERCLOCKING)) { + setAllowOverclocking(compound.getBoolean(ALLOW_OVERCLOCKING)); + } + if (compound.hasKey(OVERCLOCK_VOLTAGE)) { + this.overclockVoltage = compound.getLong(OVERCLOCK_VOLTAGE); + } else { + // Calculate overclock voltage based on old allow flag + this.overclockVoltage = this.allowOverclocking ? getMaxVoltage() : 0; + } + } } diff --git a/src/main/java/gregtech/api/capability/impl/PlayerConfigurationContext.java b/src/main/java/gregtech/api/capability/impl/PlayerConfigurationContext.java new file mode 100755 index 0000000000..4269198516 --- /dev/null +++ b/src/main/java/gregtech/api/capability/impl/PlayerConfigurationContext.java @@ -0,0 +1,51 @@ +package gregtech.api.capability.impl; + +import gregtech.api.capability.ConfigurationContext; +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.tool.IConfiguratorItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.common.capabilities.Capability; + +public class PlayerConfigurationContext implements ConfigurationContext { + + private final EntityPlayer player; + private final ItemStack configurator; + private final boolean advanced; + + public PlayerConfigurationContext(final EntityPlayer player, final ItemStack configurator) { + this.player = player; + this.configurator = configurator; + boolean isAdvanced = false; + // Review: Should this be an error (the passed item is not a configurator)? + if (configurator != null) { + final IConfiguratorItem item = configurator.getCapability(GregtechCapabilities.CAPABILITY_CONFIGURATOR, null); + if (item != null) { + isAdvanced = item.isAdvanced(); + } + } + this.advanced = isAdvanced; + } + + @Override + public boolean isAdvanced() { + return this.advanced; + } + + // Review: available via casting - not part of the generic api + public ItemStack getConfigurator() { + return this.configurator; + } + + @Override + public void sendMessage(final ITextComponent component) { + this.player.sendMessage(component); + } + + @Override + public T getCapability(final Capability capability, final EnumFacing facing) { + return isAdvanced() ? this.player.getCapability(capability, facing) : null; + } +} \ No newline at end of file diff --git a/src/main/java/gregtech/api/capability/tool/IConfiguratorItem.java b/src/main/java/gregtech/api/capability/tool/IConfiguratorItem.java new file mode 100755 index 0000000000..2c912b4056 --- /dev/null +++ b/src/main/java/gregtech/api/capability/tool/IConfiguratorItem.java @@ -0,0 +1,11 @@ +package gregtech.api.capability.tool; + +public interface IConfiguratorItem { + + default boolean isAdvanced() { + return false; + } + + boolean damageItem(int damage, boolean simulate); + +} diff --git a/src/main/java/gregtech/api/cover/CoverBehavior.java b/src/main/java/gregtech/api/cover/CoverBehavior.java index 32f5fab675..fd49bd7462 100644 --- a/src/main/java/gregtech/api/cover/CoverBehavior.java +++ b/src/main/java/gregtech/api/cover/CoverBehavior.java @@ -8,11 +8,16 @@ import codechicken.lib.vec.Matrix4; import com.google.common.collect.Lists; import gregtech.api.GTValues; +import gregtech.api.capability.ConfigurationContext; +import gregtech.api.capability.IConfigurable; import gregtech.api.gui.IUIHolder; +import gregtech.api.items.metaitem.MetaItem; +import gregtech.api.items.metaitem.MetaItem.MetaValueItem; import gregtech.api.render.SimpleSidedCubeRenderer.RenderSide; import gregtech.api.render.Textures; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; @@ -20,6 +25,7 @@ import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -33,8 +39,7 @@ *

* Can implement {@link net.minecraft.util.ITickable} to listen to meta tile entity updates */ -@SuppressWarnings("unused") -public abstract class CoverBehavior implements IUIHolder { +public abstract class CoverBehavior implements IUIHolder, IConfigurable { private CoverDefinition coverDefinition; public final ICoverable coverHolder; @@ -85,6 +90,34 @@ public void readFromNBT(NBTTagCompound tagCompound) { this.redstoneSignalOutput = tagCompound.getInteger("RedstoneSignal"); } + @Override + public ResourceLocation getConfigurationID() { + return getCoverDefinition().getCoverId(); + } + + @Override + public String getConfigurationName() { + // FIXME: how to do this properly? + final ItemStack coverStack = getCoverDefinition().getDropItemStack(); + final Item item = coverStack.getItem(); + if (item instanceof MetaItem) { + MetaItem metaItem = (MetaItem) item; + MetaItem.MetaValueItem metaValueItem = metaItem.getItem(coverStack); + return String.format("metaitem.%s.name", metaValueItem.unlocalizedName); + } + return String.format("%s.name", coverStack.getTranslationKey()); + } + + @Override + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + return new NBTTagCompound(); + } + + @Override + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound configuration) { + // nothing by default + } + public void writeInitialSyncData(PacketBuffer packetBuffer) { } diff --git a/src/main/java/gregtech/api/items/toolitem/ConfiguratorItemStat.java b/src/main/java/gregtech/api/items/toolitem/ConfiguratorItemStat.java new file mode 100755 index 0000000000..6b1d039edd --- /dev/null +++ b/src/main/java/gregtech/api/items/toolitem/ConfiguratorItemStat.java @@ -0,0 +1,40 @@ +package gregtech.api.items.toolitem; + +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.tool.IConfiguratorItem; +import gregtech.api.items.metaitem.stats.IItemCapabilityProvider; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; + +public class ConfiguratorItemStat implements IItemCapabilityProvider { + + private boolean advanced = false; + + @Override + public ICapabilityProvider createProvider(final ItemStack itemStack) { + return new CapabilityProvider(itemStack); + } + + public ConfiguratorItemStat advanced() { + this.advanced = true; + return this; + } + + private class CapabilityProvider extends AbstractToolItemCapabilityProvider implements IConfiguratorItem { + + public CapabilityProvider(final ItemStack itemStack) { + super(itemStack); + } + + @Override + public boolean isAdvanced() { + return ConfiguratorItemStat.this.advanced; + } + + @Override + protected Capability getCapability() { + return GregtechCapabilities.CAPABILITY_CONFIGURATOR; + } + } +} diff --git a/src/main/java/gregtech/api/metatileentity/MTETrait.java b/src/main/java/gregtech/api/metatileentity/MTETrait.java index 62301175ef..835459cea8 100644 --- a/src/main/java/gregtech/api/metatileentity/MTETrait.java +++ b/src/main/java/gregtech/api/metatileentity/MTETrait.java @@ -7,6 +7,8 @@ import java.util.function.Consumer; +import gregtech.api.capability.ConfigurationContext; + public abstract class MTETrait { protected MetaTileEntity metaTileEntity; @@ -39,6 +41,20 @@ public NBTTagCompound serializeNBT() { public void deserializeNBT(NBTTagCompound compound) { } + @SuppressWarnings("static-method") + protected boolean isConfigurable() { + return false; + } + + @SuppressWarnings("static-method") + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + return new NBTTagCompound(); + } + + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound compound) { + // nothing by default + } + public void writeInitialData(PacketBuffer buffer) { } diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index 72baac580a..1bd6009a27 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -10,7 +10,9 @@ import codechicken.lib.vec.Matrix4; import com.google.common.base.Preconditions; import gregtech.api.GregTechAPI; +import gregtech.api.capability.ConfigurationContext; import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IConfigurable; import gregtech.api.capability.IEnergyContainer; import gregtech.api.capability.impl.FluidHandlerProxy; import gregtech.api.capability.impl.FluidTankList; @@ -58,7 +60,7 @@ import static gregtech.api.util.InventoryUtils.simulateItemStackMerge; -public abstract class MetaTileEntity implements ICoverable { +public abstract class MetaTileEntity implements ICoverable, IConfigurable { public static final int DEFAULT_PAINTING_COLOR = 0xFFFFFF; public static final IndexedCuboid6 FULL_CUBE_COLLISION = new IndexedCuboid6(null, Cuboid6.full); @@ -804,6 +806,7 @@ public final T getCoverCapability(Capability capability, EnumFacing side) return originalCapability; } + @Override public T getCapability(Capability capability, EnumFacing side) { if (capability == GregtechTileCapabilities.CAPABILITY_COVERABLE) { return GregtechTileCapabilities.CAPABILITY_COVERABLE.cast(this); @@ -1149,6 +1152,45 @@ public void readFromNBT(NBTTagCompound data) { this.isFragile = data.getBoolean(TAG_KEY_FRAGILE); } + @Override + public ResourceLocation getConfigurationID() { + return this.metaTileEntityId; + } + + @Override + public String getConfigurationName() { + // FIXME: how to do this properly? + return String.format("%s.name", getStackForm().getTranslationKey()); + } + + @Override + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + final NBTTagCompound data = new NBTTagCompound(); + data.setInteger("FrontFacing", this.frontFacing.getIndex()); + + for (MTETrait mteTrait : this.mteTraits) { + if (mteTrait.isConfigurable()) { + data.setTag(mteTrait.getName(), mteTrait.copyConfiguration(context)); + } + } + return data; + } + + @Override + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound data) { + setFrontFacing(EnumFacing.VALUES[data.getInteger("FrontFacing")]); + + // Review: Is it possible to have mismatched traits? + for (MTETrait mteTrait : this.mteTraits) { + if (mteTrait.isConfigurable()) { + final NBTTagCompound traitCompound = data.getCompoundTag(mteTrait.getName()); + if (traitCompound != null) { + mteTrait.pasteConfiguration(context, traitCompound); + } + } + } + } + @Override public boolean isValid() { return getHolder() != null && getHolder().isValid(); diff --git a/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java index a7765adbcb..b0fd133e30 100644 --- a/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java @@ -4,6 +4,7 @@ import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; +import gregtech.api.capability.ConfigurationContext; import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IActiveOutputSide; import gregtech.api.capability.impl.EnergyContainerHandler; @@ -187,7 +188,10 @@ public T getCapability(Capability capability, EnumFacing side) { return GregtechTileCapabilities.CAPABILITY_ACTIVE_OUTPUT_SIDE.cast(this); } return null; + } else if (capability == GregtechTileCapabilities.CAPABILITY_CONFIGURABLE) { + return GregtechTileCapabilities.CAPABILITY_CONFIGURABLE.cast(this); } + return super.getCapability(capability, side); } @@ -212,6 +216,25 @@ public void readFromNBT(NBTTagCompound data) { this.allowInputFromOutputSide = data.getBoolean("AllowInputFromOutputSide"); } + @Override + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + final NBTTagCompound data = super.copyConfiguration(context); + data.setInteger("OutputFacing", getOutputFacing().getIndex()); + data.setBoolean("AutoOutputItems", this.autoOutputItems); + data.setBoolean("AutoOutputFluids", this.autoOutputFluids); + data.setBoolean("AllowInputFromOutputSide", this.allowInputFromOutputSide); + return data; + } + + @Override + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound data) { + super.pasteConfiguration(context, data); + setOutputFacing(EnumFacing.VALUES[data.getInteger("OutputFacing")]); + setAutoOutputItems(data.getBoolean("AutoOutputItems")); + setAutoOutputFluids(data.getBoolean("AutoOutputFluids")); + setAllowInputFromOutputSide(data.getBoolean("AllowInputFromOutputSide")); + } + @Override public void writeInitialSyncData(PacketBuffer buf) { super.writeInitialSyncData(buf); diff --git a/src/main/java/gregtech/common/covers/CoverConveyor.java b/src/main/java/gregtech/common/covers/CoverConveyor.java index d205875a92..58f0b9a40f 100644 --- a/src/main/java/gregtech/common/covers/CoverConveyor.java +++ b/src/main/java/gregtech/common/covers/CoverConveyor.java @@ -8,6 +8,7 @@ import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; import gregtech.api.GTValues; +import gregtech.api.capability.ConfigurationContext; import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IControllable; import gregtech.api.capability.impl.ItemHandlerDelegate; @@ -401,6 +402,9 @@ public T getCapability(Capability capability, T defaultValue) { if(capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); } + if (capability == GregtechTileCapabilities.CAPABILITY_CONFIGURABLE) { + return GregtechTileCapabilities.CAPABILITY_CONFIGURABLE.cast(this); + } return defaultValue; } @@ -482,6 +486,38 @@ public void readFromNBT(NBTTagCompound tagCompound) { } } + @Override + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + final NBTTagCompound tagCompound = super.copyConfiguration(context); + tagCompound.setInteger("TransferRate", this.transferRate); + tagCompound.setInteger("ConveyorMode", this.conveyorMode.ordinal()); + tagCompound.setInteger("ManualImportExportMode", this.manualImportExportMode.ordinal()); + tagCompound.setTag("Filter", this.itemFilterContainer.copyConfiguration(context)); + return tagCompound; + } + + @Override + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound tagCompound) { + super.pasteConfiguration(context, tagCompound); + setTransferRate(tagCompound.getInteger("TransferRate")); + setConveyorMode(ConveyorMode.values()[tagCompound.getInteger("ConveyorMode")]); + //LEGACY SAVE FORMAT SUPPORT + if (tagCompound.hasKey("AllowManualIO")) { + setManualImportExportMode(tagCompound.getBoolean("AllowManualIO") + ? ManualImportExportMode.FILTERED + : ManualImportExportMode.DISABLED); + } + if (tagCompound.hasKey("ManualImportExportMode")) { + setManualImportExportMode(ManualImportExportMode.values()[tagCompound.getInteger("ManualImportExportMode")]); + } + if (tagCompound.hasKey("FilterInventory")) { + this.itemFilterContainer.pasteConfiguration(context, tagCompound); + } else { + final NBTTagCompound filterComponent = tagCompound.getCompoundTag("Filter"); + this.itemFilterContainer.pasteConfiguration(context, filterComponent); + } + } + public enum ConveyorMode implements IStringSerializable { IMPORT("cover.conveyor.mode.import"), EXPORT("cover.conveyor.mode.export"); diff --git a/src/main/java/gregtech/common/covers/filter/ItemFilterContainer.java b/src/main/java/gregtech/common/covers/filter/ItemFilterContainer.java index 1572a25728..d9de5aecde 100644 --- a/src/main/java/gregtech/common/covers/filter/ItemFilterContainer.java +++ b/src/main/java/gregtech/common/covers/filter/ItemFilterContainer.java @@ -1,22 +1,32 @@ package gregtech.common.covers.filter; +import gregtech.api.capability.ConfigurationContext; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.*; +import gregtech.api.util.GTUtility; import gregtech.api.util.IDirtyNotifiable; import gregtech.api.util.ItemStackKey; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; import javax.annotation.Nonnull; + +import java.util.Objects; import java.util.Set; import java.util.function.Consumer; public class ItemFilterContainer implements INBTSerializable { + private static final String WRONG_FILTER = "metaitem.configurator.wrong_filter"; + private final ItemStackHandler filterInventory; private final ItemFilterWrapper filterWrapper; private int maxStackSizeLimit = 1; @@ -129,6 +139,71 @@ public boolean testItemStack(ItemStack itemStack) { return matchItemStack(itemStack) != null; } + /** + * Remove the filter into an external inventory + * + * @param externalInventory the external inventory + * @param simulate true to simulate the clear + * @return true when there is no filter or the filter can be placed in the inventory + */ + public boolean clearFilter(final IItemHandler externalInventory, final boolean simulate) { + final ItemStack currentFilter = this.filterInventory.getStackInSlot(0); + if (currentFilter.isEmpty()) { + return true; + } + if (!ItemHandlerHelper.insertItemStacked(externalInventory, currentFilter, simulate).isEmpty()) { + return false; + } + if (!simulate) { + this.filterInventory.extractItem(0, Integer.MAX_VALUE, false); + } + return true; + } + + /** + * Swaps the filter with one from an external inventory + * + * @param requiredFilter the filter to be used + * @param externalInventory the external inventory + * @return true when the filter can be obtained from the external inventory + */ + public boolean swapFilter(final ItemStack requiredFilter, final IItemHandler externalInventory) { + if (!this.filterInventory.isItemValid(0, requiredFilter)) { + return false; + } + if (!extractItem(requiredFilter, externalInventory, true)) { + return false; + } + // Review: This will stop the swap if there is no space, even though there will be space freed when the new filter is removed + // but not doing this check will mean we void items for read only inventories + if (!clearFilter(externalInventory, true)) { + return false; + } + extractItem(requiredFilter, externalInventory, false); + clearFilter(externalInventory, false); + this.filterInventory.insertItem(0, requiredFilter, false); + return true; + } + + private static boolean extractItem(final ItemStack itemStack, final IItemHandler itemHandler, final boolean simulate) { + final int count = itemStack.getCount(); + for (int i = 0; i < itemHandler.getSlots(); ++i) { + final ItemStack stackInSlot = itemHandler.extractItem(i, count, true); + if (equalsIgnoreNBT(itemStack, stackInSlot)) { + if (!simulate) { + itemHandler.extractItem(i, count, false); + } + return true; + } + } + return false; + } + + private static boolean equalsIgnoreNBT(final ItemStack one, final ItemStack two) { + return one.getItem().equals(two.getItem()) && one.getCount() == two.getCount() && + GTUtility.getActualItemDamageFromStack(one) == GTUtility.getActualItemDamageFromStack(two); + } + @Override public NBTTagCompound serializeNBT() { NBTTagCompound tagCompound = new NBTTagCompound(); @@ -165,4 +240,66 @@ public void deserializeNBT(NBTTagCompound tagCompound) { } } } + + public NBTTagCompound copyConfiguration(final ConfigurationContext context) { + NBTTagCompound tagCompound = new NBTTagCompound(); + tagCompound.setTag("FilterInventory", this.filterInventory.serializeNBT()); + tagCompound.setBoolean("IsBlacklist", this.filterWrapper.isBlacklistFilter()); + tagCompound.setInteger("MaxStackSize", this.maxStackSizeLimit); + tagCompound.setInteger("TransferStackSize", this.transferStackSize); + final ItemFilter filter = this.filterWrapper.getItemFilter(); + if (filter != null) { + final NBTTagCompound filterInventory = new NBTTagCompound(); + filter.writeToNBT(filterInventory); + tagCompound.setTag("Filter", filterInventory); + tagCompound.setString("FilterClassName", filter.getClass().getName()); + } + return tagCompound; + } + + public void pasteConfiguration(final ConfigurationContext context, final NBTTagCompound tagCompound) { + ItemFilter filter = this.filterWrapper.getItemFilter(); + final String configClassName = tagCompound.getString("FilterClassName"); + final String filterClassName = filter != null ? filter.getClass().getName() : null; + if (!Objects.equals(configClassName, filterClassName) && !swapFilter(context, tagCompound)) { + context.sendMessage(new TextComponentTranslation(WRONG_FILTER)); + return; + } + + this.filterInventory.deserializeNBT(tagCompound.getCompoundTag("FilterInventory")); + this.filterWrapper.setBlacklistFilter(tagCompound.getBoolean("IsBlacklist")); + if (tagCompound.hasKey("MaxStackSize")) { + setMaxStackSize(tagCompound.getInteger("MaxStackSize")); + } + if (tagCompound.hasKey("TransferStackSize")) { + setTransferStackSize(tagCompound.getInteger("TransferStackSize")); + } + filter = this.filterWrapper.getItemFilter(); + if (filter != null) { + //LEGACY SAVE FORMAT SUPPORT + if (tagCompound.hasKey("ItemFilter") || + tagCompound.hasKey("OreDictionaryFilter")) { + filter.readFromNBT(tagCompound); + } else { + final NBTTagCompound filterInventory = tagCompound.getCompoundTag("Filter"); + filter.readFromNBT(filterInventory); + } + } + } + + private boolean swapFilter(final ConfigurationContext context, final NBTTagCompound tagCompound) { + final IItemHandler externalInventory = context.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); + if (externalInventory == null) { + return false; + } + + final ItemStackHandler requiredFilters = new ItemStackHandler(1); + requiredFilters.deserializeNBT(tagCompound.getCompoundTag("FilterInventory")); + final ItemStack requiredFilter = requiredFilters.getStackInSlot(0); + + if (requiredFilter.isEmpty()) { + return clearFilter(externalInventory, false); + } + return swapFilter(requiredFilter, externalInventory); + } } diff --git a/src/main/java/gregtech/common/items/MetaTool.java b/src/main/java/gregtech/common/items/MetaTool.java index 177a3dd270..236cecd880 100644 --- a/src/main/java/gregtech/common/items/MetaTool.java +++ b/src/main/java/gregtech/common/items/MetaTool.java @@ -3,6 +3,7 @@ import gregtech.api.GTValues; import gregtech.api.items.ToolDictNames; import gregtech.api.items.metaitem.ElectricStats; +import gregtech.api.items.toolitem.ConfiguratorItemStat; import gregtech.api.items.toolitem.ScrewdriverItemStat; import gregtech.api.items.toolitem.SoftMalletItemStat; import gregtech.api.items.toolitem.ToolMetaItem; @@ -70,7 +71,9 @@ public void registerSubItems() { FILE = addItem(9, "tool.file").setToolStats(new ToolFile()) .setFullRepairCost(2) - .addOreDict(ToolDictNames.craftingToolFile); + .addOreDict(ToolDictNames.craftingToolFile) + // FIXME file is not the configurator + .addComponents(new ConfiguratorItemStat().advanced()); CROWBAR = addItem(10, "tool.crowbar").setToolStats(new ToolCrowbar()) .setFullRepairCost(1.5) diff --git a/src/main/java/gregtech/common/items/behaviors/ConfiguratorBehavior.java b/src/main/java/gregtech/common/items/behaviors/ConfiguratorBehavior.java new file mode 100755 index 0000000000..592a18f5f4 --- /dev/null +++ b/src/main/java/gregtech/common/items/behaviors/ConfiguratorBehavior.java @@ -0,0 +1,152 @@ +package gregtech.common.items.behaviors; + +import java.util.List; + +import codechicken.lib.raytracer.CuboidRayTraceResult; +import codechicken.lib.raytracer.RayTracer; +import gregtech.api.capability.ConfigurationContext; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IConfigurable; +import gregtech.api.capability.impl.PlayerConfigurationContext; +import gregtech.api.cover.ICoverable; +import gregtech.api.items.metaitem.stats.IItemBehaviour; +import gregtech.api.util.GTUtility; +import gregtech.common.items.behaviors.ModeSwitchBehavior.ILocalizationKey; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class ConfiguratorBehavior implements IItemBehaviour { + + private static final String CONFIGURATION = "metaitem.configurator.configuration"; + private static final String COPY = "metaitem.configurator.copy"; + private static final String NO_CONFIGURATION = "metaitem.configurator.no_configuration"; + private static final String NOT_CONFIGURABLE = "metaitem.configurator.not_configurable"; + private static final String PASTE = "metaitem.configurator.paste"; + private static final String WRONG_CONFIGURABLE1 = "metaitem.configurator.wrong_configurable1"; + private static final String WRONG_CONFIGURABLE2 = "metaitem.configurator.wrong_configurable2"; + + public static final ModeSwitchBehavior CONFIGURATOR_MODE_SWITCH_BEHAVIOR = new ModeSwitchBehavior<>(ConfiguratorMode.class); + + private static final String TAG_NAME = "GT.Configurator"; + private static final String CONFIGURATION_ID = "GT.ConfigurationID"; + private static final String CONFIGURATION_NAME = "GT.ConfigurationName"; + private final int cost; + + public ConfiguratorBehavior(final int cost) { + this.cost = cost; + } + + @Override + public EnumActionResult onItemUseFirst(final EntityPlayer player, final World world, final BlockPos pos, final EnumFacing side, final float hitX, final float hitY, final float hitZ, final EnumHand hand) { + // Everything gets done on the server side + if (world.isRemote) { + return EnumActionResult.SUCCESS; + } + + final ItemStack toolStack = player.getHeldItem(hand); + + // Only acts on tile entities + final TileEntity tileEntity = world.getTileEntity(pos); + if (tileEntity == null) { + player.sendMessage(new TextComponentTranslation(NOT_CONFIGURABLE)); + return EnumActionResult.PASS; + } + + // We got told a side, but let's use the mode and ray tracing to figure out what the user really wants + final ConfiguratorMode mode = CONFIGURATOR_MODE_SWITCH_BEHAVIOR.getModeFromItemStack(toolStack); + EnumFacing checkSide = null; // machine mode doesn't check a side + if (mode == ConfiguratorMode.COVER) { + final CuboidRayTraceResult rayTraceResult = (CuboidRayTraceResult) RayTracer.retraceBlock(world, player, pos); + checkSide = ICoverable.determineGridSideHit(rayTraceResult); + } + + // Get the capability of the relevant machine/cover + final IConfigurable configurable = tileEntity.getCapability(GregtechTileCapabilities.CAPABILITY_CONFIGURABLE, checkSide); + if (configurable == null) { + player.sendMessage(new TextComponentTranslation(NOT_CONFIGURABLE)); + return EnumActionResult.PASS; + } + + final ConfigurationContext context = new PlayerConfigurationContext(player, toolStack); + + // Shift Right Click is save + final boolean isShiftClick = player.isSneaking(); + if (isShiftClick) { + final NBTTagCompound configuration = configurable.copyConfiguration(context); + // Didn't get a configuration for some reason. Should this be a fail? + if (configuration == null) { + player.sendMessage(new TextComponentTranslation(NOT_CONFIGURABLE)); + return EnumActionResult.PASS; + } + // Remember the id and name of the machine/cover + final String machineID = configurable.getConfigurationID().toString(); + configuration.setString(CONFIGURATION_ID, machineID); + final String machineName = configurable.getConfigurationName(); + configuration.setString(CONFIGURATION_NAME, machineName); + // Save the configuration in the item + final NBTTagCompound itemTag = toolStack.getTagCompound(); + itemTag.setTag(TAG_NAME, configuration); + player.sendMessage(new TextComponentTranslation(COPY).appendSibling(new TextComponentTranslation(machineName))); + } else { + // Configurator doesn't have a saved configuration + final NBTTagCompound configuration = toolStack.getSubCompound(TAG_NAME); + if (configuration == null) { + player.sendMessage(new TextComponentTranslation(NO_CONFIGURATION)); + return EnumActionResult.PASS; + } + // Check the saved config has the same id as the target machine/cover + final String machineID = configurable.getConfigurationID().toString(); + final String savedID = configuration.getString(CONFIGURATION_ID); + final String machineName = configurable.getConfigurationName(); + final String savedName = configuration.getString(CONFIGURATION_NAME); + if (!machineID.equals(savedID)) { + player.sendMessage(new TextComponentTranslation(WRONG_CONFIGURABLE1) + .appendSibling(new TextComponentTranslation(savedName)) + .appendSibling(new TextComponentTranslation(WRONG_CONFIGURABLE2)) + .appendSibling(new TextComponentTranslation(machineName))); + return EnumActionResult.FAIL; + } + // Apply the configuration, any warnings should be sent to chat + configurable.pasteConfiguration(context, configuration); + player.sendMessage(new TextComponentTranslation(PASTE).appendSibling(new TextComponentTranslation(savedName))); + } + GTUtility.doDamageItem(toolStack, this.cost, false); + return EnumActionResult.SUCCESS; + } + + @Override + public void addInformation(final ItemStack toolStack, final List lines) { + final NBTTagCompound configuration = toolStack.getSubCompound(TAG_NAME); + if (configuration == null) { + lines.add(I18n.format(NO_CONFIGURATION)); + } else { + final String configName = configuration.getString(CONFIGURATION_NAME); + lines.add(I18n.format(CONFIGURATION, I18n.format(configName))); + } + } + + private enum ConfiguratorMode implements ILocalizationKey { + COVER("metaitem.configurator.mode.cover"), + MACHINE("metaitem.configurator.mode.machine"); + + private final String localizationKey; + + ConfiguratorMode(final String localizationKey) { + this.localizationKey = localizationKey; + } + + @Override + public String getUnlocalizedName() { + return this.localizationKey; + } + } +} diff --git a/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java b/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java index 3430e1aa7f..81c9121d51 100644 --- a/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java +++ b/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java @@ -93,8 +93,10 @@ public static boolean useGridForRayTraceResult(RayTraceResult result) { } public static boolean shouldDrawOverlayForItem(ItemStack itemStack, TileEntity tileEntity) { - if(tileEntity instanceof MetaTileEntityHolder && - itemStack.hasCapability(GregtechCapabilities.CAPABILITY_WRENCH, null)) { + if (tileEntity instanceof MetaTileEntityHolder && ( + itemStack.hasCapability(GregtechCapabilities.CAPABILITY_WRENCH, null) || + itemStack.hasCapability(GregtechCapabilities.CAPABILITY_CONFIGURATOR, null) + )) { return true; } if(tileEntity.hasCapability(GregtechTileCapabilities.CAPABILITY_COVERABLE, null)) { diff --git a/src/main/java/gregtech/common/tools/DamageValues.java b/src/main/java/gregtech/common/tools/DamageValues.java index 1895bb3b53..d27c875718 100644 --- a/src/main/java/gregtech/common/tools/DamageValues.java +++ b/src/main/java/gregtech/common/tools/DamageValues.java @@ -10,4 +10,5 @@ public class DamageValues { public static final int DAMAGE_FOR_SOFT_HAMMER = 3; public static final int DAMAGE_FOR_HOE = 2; public static final int DAMAGE_FOR_PLUNGER = 1; + public static final int DAMAGE_FOR_CONFIGURATOR = 1; } diff --git a/src/main/java/gregtech/common/tools/ToolFile.java b/src/main/java/gregtech/common/tools/ToolFile.java index e866c426e4..6efbb671c8 100644 --- a/src/main/java/gregtech/common/tools/ToolFile.java +++ b/src/main/java/gregtech/common/tools/ToolFile.java @@ -1,5 +1,7 @@ package gregtech.common.tools; +import gregtech.api.items.metaitem.MetaItem.MetaValueItem; +import gregtech.common.items.behaviors.ConfiguratorBehavior; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.ItemStack; @@ -28,4 +30,11 @@ public boolean canMineBlock(IBlockState block, ItemStack stack) { block.getMaterial() == Material.CIRCUITS; } + @SuppressWarnings("rawtypes") + @Override + // FIXME file is not the configurator + public void onStatsAddedToTool(MetaValueItem metaValueItem) { + metaValueItem.addComponents(new ConfiguratorBehavior(DamageValues.DAMAGE_FOR_CONFIGURATOR), ConfiguratorBehavior.CONFIGURATOR_MODE_SWITCH_BEHAVIOR); + } + } diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 411412f710..c5d7d1d043 100755 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -684,6 +684,17 @@ metaitem.turbine_rotor.name=%s Turbine Rotor metaitem.turbine_rotor.tooltip=Turbine Rotors for your power station metaitem.tool.magnifying_glass.name=%s Magnifying Glass +metaitem.configurator.configuration=Configuration: %s +metaitem.configurator.copy=Configuration Copied: +metaitem.configurator.no_configuration=No configuration in item +metaitem.configurator.mode.cover=Cover - uses the grid +metaitem.configurator.mode.machine=Machine - ignores the grid +metaitem.configurator.not_configurable=Not configurable +metaitem.configurator.paste=Configuration Applied: +metaitem.configurator.wrong_configurable1=Configuration in item +metaitem.configurator.wrong_configurable2= does not match +metaitem.configurator.wrong_filter=Configuration filter type doesn't match + metaitem.jack_hammer.mode.three_by_three=3x3 Panel metaitem.jack_hammer.mode.vertical_line=Vertical Line metaitem.jack_hammer.mode.horizontal_line=Horizontal Line