diff --git a/README.md b/README.md index 94f34c9..38bd48d 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,30 @@ BuildCraft の Builder を拡張し、建築に必要な資材を EMC で支払 - GUI の EMC スロットにアイテムを入れると、Transmutation Table と同様に EMC に変換されます。 - レシピ: Builder + Transmutation Table(不定形) +### CE クアーリー + +BuildCraft の Quarry の強化版です。動作は BuildCraft 7 の Quarry と同じく、フレームを建ててからアームで掘り、掘ったアイテムを隣接するチェストやパイプに送ります。 + +- **採掘強化型クアーリー(CEQ-2)**: バッテリーが BuildCraft の Quarry の 2 倍で、その分アームが速く動きます。 + - マーカーがなければ、本体の後ろ側を 64x64 の範囲で掘ります。スニークしながら置くと、範囲が左右反転します。 + - y=5 で止まるので、岩盤層は荒らしません。 + - 溶岩はスキップするだけで、その下の列も掘ります。 + - 前回の位置から探索を続けます。レンチで右クリックすると、掘り終えた後でも最初から掘り直します。 + - チャンクロード機能はありません。 +- **溶岩除去型クアーリー(CEQ-3)**: CEQ-2 の機能に加えて、範囲内の溶岩源を除去します。 +- **液体対策型クアーリー(CEQ-4)**: CEQ-3 の機能に加えて、アームに隣接する水・溶岩・オイルなどの液体をガラスに変えながら掘ります。受電量は 5 倍です。 + +レシピ(CE と同じ配置で、素材を BuildCraft 7 のものに置き換えています): + +- CEQ-2: 上段 鉄歯車・レッドストーン・鉄歯車 / 中段 金歯車・鉄歯車・金歯車 / 下段 ダイヤ歯車・Quarry・ダイヤ歯車 +- CEQ-3: 上段 エンダーパール・タンク・エンダーパール / 中段 ダイヤチップセット・ポンプ・ダイヤチップセット / 下段 ダイヤ AND ゲート・CEQ-2・ダイヤ AND ゲート +- CEQ-4: 上段 ガラス×3 / 中段 水バケツ・CEQ-3・溶岩バケツ / 下段 タンク・鉄 AND ゲート・タンク + +`config/cemodern.cfg` の `quarry` で、初期範囲の大きさ(`defaultArea`)、本体の位置(`defaultPosition`)、掘る深さ(`miningYmin`)を変えられます。 + ## 必要な Mod -- BuildCraft 7.1.x(Builders) +- BuildCraft 7.1.x(Builders, Factory, Silicon, Transport) - ProjectE ## ビルド diff --git a/src/main/java/net/kanawo/cemodern/CEConfig.java b/src/main/java/net/kanawo/cemodern/CEConfig.java new file mode 100644 index 0000000..b8aeaca --- /dev/null +++ b/src/main/java/net/kanawo/cemodern/CEConfig.java @@ -0,0 +1,53 @@ +package net.kanawo.cemodern; + +import java.io.File; + +import net.minecraftforge.common.config.Configuration; + +/** Settings read from config/cemodern.cfg. */ +public final class CEConfig { + + private static final String CATEGORY_QUARRY = "quarry"; + + /** Side length of the area a CE quarry digs when no marker is next to it. */ + public static int quarryDefaultSize = 64; + /** Where the quarry sits along the edge of its default area, counted from one corner. */ + public static int quarryDefaultPosition = 0; + /** Lowest Y level CE quarries dig down to. Bedrock is at 0 to 4. */ + public static int quarryMinY = 5; + + private CEConfig() {} + + public static void load(File file) { + Configuration config = new Configuration(file); + + quarryDefaultSize = config.getInt( + "defaultArea", + CATEGORY_QUARRY, + quarryDefaultSize, + 3, + 130, + "Side length of the area a CE quarry digs when no marker is next to it."); + quarryDefaultPosition = config.getInt( + "defaultPosition", + CATEGORY_QUARRY, + quarryDefaultPosition, + 0, + 129, + "Where the quarry sits along the edge of its default area, counted from one corner." + + " Sneak while placing it to count from the other corner."); + quarryMinY = config.getInt( + "miningYmin", + CATEGORY_QUARRY, + quarryMinY, + 0, + 255, + "Lowest Y level CE quarries dig down to. Bedrock is at 0 to 4."); + + quarryDefaultPosition = Math.min(quarryDefaultPosition, quarryDefaultSize - 1); + + if (config.hasChanged()) { + config.save(); + } + } +} diff --git a/src/main/java/net/kanawo/cemodern/CEModern.java b/src/main/java/net/kanawo/cemodern/CEModern.java index c1a09c3..e209553 100644 --- a/src/main/java/net/kanawo/cemodern/CEModern.java +++ b/src/main/java/net/kanawo/cemodern/CEModern.java @@ -13,7 +13,8 @@ import cpw.mods.fml.common.event.FMLPreInitializationEvent; version = Tags.VERSION, name = "CE-modern", acceptedMinecraftVersions = "[1.7.10]", - dependencies = "required-after:BuildCraft|Builders;required-after:ProjectE") + dependencies = "required-after:BuildCraft|Builders;required-after:BuildCraft|Factory;" + + "required-after:BuildCraft|Silicon;required-after:BuildCraft|Transport;required-after:ProjectE") public class CEModern { public static final String MODID = "cemodern"; diff --git a/src/main/java/net/kanawo/cemodern/ClientProxy.java b/src/main/java/net/kanawo/cemodern/ClientProxy.java index a5de47d..0a9fe46 100644 --- a/src/main/java/net/kanawo/cemodern/ClientProxy.java +++ b/src/main/java/net/kanawo/cemodern/ClientProxy.java @@ -1,9 +1,13 @@ package net.kanawo.cemodern; +import net.kanawo.cemodern.entity.EntityCEQuarryArm; +import net.kanawo.cemodern.tile.TileCEQuarry; import net.kanawo.cemodern.tile.TileEMCBuilder; +import buildcraft.core.lib.render.RenderVoid; import buildcraft.core.render.RenderBuilder; import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.event.FMLInitializationEvent; public class ClientProxy extends CommonProxy { @@ -15,5 +19,12 @@ public class ClientProxy extends CommonProxy { // The Builder's own renderer (RenderBuilderTile) also draws BuildCraft's lit top while building. Its base // renderer draws only the area box, path lasers and flying items. ClientRegistry.bindTileEntitySpecialRenderer(TileEMCBuilder.class, new RenderBuilder()); + + // The quarries draw their area box and the frames flying into place. The arm is drawn by its parts. + RenderBuilder quarryRenderer = new RenderBuilder(); + ClientRegistry.bindTileEntitySpecialRenderer(TileCEQuarry.Fast.class, quarryRenderer); + ClientRegistry.bindTileEntitySpecialRenderer(TileCEQuarry.Lava.class, quarryRenderer); + ClientRegistry.bindTileEntitySpecialRenderer(TileCEQuarry.Fluid.class, quarryRenderer); + RenderingRegistry.registerEntityRenderingHandler(EntityCEQuarryArm.class, new RenderVoid()); } } diff --git a/src/main/java/net/kanawo/cemodern/CommonProxy.java b/src/main/java/net/kanawo/cemodern/CommonProxy.java index ad97bc0..a829433 100644 --- a/src/main/java/net/kanawo/cemodern/CommonProxy.java +++ b/src/main/java/net/kanawo/cemodern/CommonProxy.java @@ -1,13 +1,26 @@ package net.kanawo.cemodern; +import net.kanawo.cemodern.block.BlockCEQuarry; import net.kanawo.cemodern.block.BlockEMCBuilder; import net.kanawo.cemodern.block.SchematicEMCBuilder; import net.kanawo.cemodern.gui.GuiHandler; +import net.kanawo.cemodern.recipe.GateRecipe; +import net.kanawo.cemodern.tile.QuarryType; +import net.kanawo.cemodern.tile.TileCEQuarry; import net.kanawo.cemodern.tile.TileEMCBuilder; +import net.minecraft.init.Items; import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.RecipeSorter; +import net.minecraftforge.oredict.RecipeSorter.Category; +import net.minecraftforge.oredict.ShapedOreRecipe; import buildcraft.BuildCraftBuilders; +import buildcraft.BuildCraftFactory; import buildcraft.api.blueprints.BuilderAPI; +import buildcraft.builders.schematics.SchematicBuilderLike; +import buildcraft.transport.gates.GateDefinition.GateLogic; +import buildcraft.transport.gates.GateDefinition.GateMaterial; +import buildcraft.transport.gates.ItemGate; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.network.NetworkRegistry; @@ -17,21 +30,100 @@ import moze_intel.projecte.gameObjs.ObjHandler; public class CommonProxy { public static BlockEMCBuilder emcBuilderBlock; + public static BlockCEQuarry quarry2Block; + public static BlockCEQuarry quarry3Block; + public static BlockCEQuarry quarry4Block; public void preInit(FMLPreInitializationEvent event) { + CEConfig.load(event.getSuggestedConfigurationFile()); + emcBuilderBlock = new BlockEMCBuilder(); GameRegistry.registerBlock(emcBuilderBlock, "emcBuilder"); GameRegistry.registerTileEntity(TileEMCBuilder.class, CEModern.MODID + ":EMCBuilder"); + + quarry2Block = registerQuarry(QuarryType.FAST, TileCEQuarry.Fast.class); + quarry3Block = registerQuarry(QuarryType.LAVA, TileCEQuarry.Lava.class); + quarry4Block = registerQuarry(QuarryType.FLUID, TileCEQuarry.Fluid.class); + } + + private static BlockCEQuarry registerQuarry(QuarryType type, Class extends TileCEQuarry> tile) { + BlockCEQuarry block = new BlockCEQuarry(type); + GameRegistry.registerBlock(block, type.name); + GameRegistry.registerTileEntity(tile, CEModern.MODID + ":" + type.name); + return block; } public void init(FMLInitializationEvent event) { NetworkRegistry.INSTANCE.registerGuiHandler(CEModern.instance, new GuiHandler()); BuilderAPI.schematicRegistry.registerSchematicBlock(emcBuilderBlock, SchematicEMCBuilder.class); + BuilderAPI.schematicRegistry.registerSchematicBlock(quarry2Block, SchematicBuilderLike.class); + BuilderAPI.schematicRegistry.registerSchematicBlock(quarry3Block, SchematicBuilderLike.class); + BuilderAPI.schematicRegistry.registerSchematicBlock(quarry4Block, SchematicBuilderLike.class); GameRegistry.addShapelessRecipe( new ItemStack(emcBuilderBlock), BuildCraftBuilders.builderBlock, ObjHandler.transmuteStone); + + RecipeSorter.register(CEModern.MODID + ":gate", GateRecipe.class, Category.SHAPED, "after:forge:shapedore"); + + // CE's recipes, with BuildCraft 7's items in place of BuildCraft 3's. + GameRegistry.addRecipe( + new ShapedOreRecipe( + new ItemStack(quarry2Block), + "iri", + "gig", + "dqd", + 'r', + "dustRedstone", + 'i', + "gearIron", + 'g', + "gearGold", + 'd', + "gearDiamond", + 'q', + BuildCraftBuilders.quarryBlock)); + GameRegistry.addRecipe( + new GateRecipe( + new ItemStack(quarry3Block), + GateMaterial.DIAMOND, + GateLogic.AND, + "ete", + "cpc", + "gqg", + 'e', + Items.ender_pearl, + 't', + BuildCraftFactory.tankBlock, + 'p', + BuildCraftFactory.pumpBlock, + 'q', + quarry2Block, + 'c', + "chipsetDiamond", + 'g', + ItemGate.makeGateItem(GateMaterial.DIAMOND, GateLogic.AND))); + GameRegistry.addRecipe( + new GateRecipe( + new ItemStack(quarry4Block), + GateMaterial.IRON, + GateLogic.AND, + "ggg", + "wql", + "tit", + 'g', + "blockGlass", + 'w', + Items.water_bucket, + 'l', + Items.lava_bucket, + 'q', + quarry3Block, + 't', + BuildCraftFactory.tankBlock, + 'i', + ItemGate.makeGateItem(GateMaterial.IRON, GateLogic.AND))); } } diff --git a/src/main/java/net/kanawo/cemodern/block/BlockCEQuarry.java b/src/main/java/net/kanawo/cemodern/block/BlockCEQuarry.java new file mode 100644 index 0000000..87e9dee --- /dev/null +++ b/src/main/java/net/kanawo/cemodern/block/BlockCEQuarry.java @@ -0,0 +1,111 @@ +package net.kanawo.cemodern.block; + +import java.util.ArrayList; + +import net.kanawo.cemodern.CEModern; +import net.kanawo.cemodern.tile.QuarryType; +import net.kanawo.cemodern.tile.TileCEQuarry; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import buildcraft.BuildCraftBuilders; +import buildcraft.api.tools.IToolWrench; +import buildcraft.core.lib.block.BlockBuildCraft; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * A CE quarry. Like BuildCraft's quarry it faces away from the placer, digs the area behind it, restarts when + * wrenched, and takes its frame with it when broken. + *
+ * Textures are looked up as textures/blocks/{quarry2,quarry3,quarry4}/{front,top,side}.png. The side texture is
+ * also used for the back and the bottom.
+ */
+public class BlockCEQuarry extends BlockBuildCraft {
+
+ public final QuarryType type;
+
+ public BlockCEQuarry(QuarryType type) {
+ super(Material.iron);
+ this.type = type;
+
+ setHardness(10F);
+ setResistance(10F);
+ setStepSound(soundTypeAnvil);
+ setRotatable(true);
+ setBlockName("ce" + Character.toUpperCase(type.name.charAt(0)) + type.name.substring(1));
+ }
+
+ @Override
+ public TileEntity createNewTileEntity(World world, int metadata) {
+ return type.createTile();
+ }
+
+ /**
+ * Registers the icons directly. BlockBuildCraft's lookup would fall back to a missing "default" texture for the
+ * bottom, which has no texture of its own.
+ */
+ @Override
+ @SideOnly(Side.CLIENT)
+ public void registerBlockIcons(IIconRegister register) {
+ String prefix = CEModern.MODID + ":" + type.name + "/";
+ IIcon side = register.registerIcon(prefix + "side");
+
+ // Indexed by side: bottom, top, front, back, left, right.
+ icons = new IIcon[16][];
+ icons[0] = new IIcon[] { side, register.registerIcon(prefix + "top"), register.registerIcon(prefix + "front"),
+ side, side, side };
+ }
+
+ @Override
+ public ArrayList
+ * It only draws the arm: three beams and the drill head, made of BuildCraft's {@link EntityBlock}s. The quarry spawns
+ * one on each side and moves its head. The entity is not registered, so it is neither sent to clients nor saved.
+ */
+public class EntityCEQuarryArm extends Entity {
+
+ private TileCEQuarry parent;
+
+ private double armSizeX;
+ private double armSizeZ;
+ private double xRoot;
+ private double yRoot;
+ private double zRoot;
+
+ private int headX, headY, headZ;
+ private EntityBlock xArm, yArm, zArm, head;
+
+ public EntityCEQuarryArm(World world) {
+ super(world);
+ makeParts(world);
+ noClip = true;
+ }
+
+ public EntityCEQuarryArm(World world, double x, double y, double z, double width, double height,
+ TileCEQuarry parent) {
+ this(world);
+ setPositionAndRotation(parent.xCoord, parent.yCoord, parent.zCoord, 0, 0);
+ this.xRoot = x;
+ this.yRoot = y;
+ this.zRoot = z;
+ this.motionX = 0.0;
+ this.motionY = 0.0;
+ this.motionZ = 0.0;
+ setArmSize(width, height);
+ setHead(x, y - 2, z);
+ this.parent = parent;
+ parent.setArm(this);
+ updatePosition();
+ }
+
+ public void setHead(double x, double y, double z) {
+ this.headX = (int) (x * 32D);
+ this.headY = (int) (y * 32D);
+ this.headZ = (int) (z * 32D);
+ }
+
+ private void setArmSize(double x, double z) {
+ armSizeX = x;
+ xArm.iSize = x;
+ armSizeZ = z;
+ zArm.kSize = z;
+ updatePosition();
+ }
+
+ private void makeParts(World world) {
+ xArm = BuilderProxy.proxy.newDrill(world, 0, 0, 0, 1, 0.5, 0.5, true);
+ yArm = BuilderProxy.proxy.newDrill(world, 0, 0, 0, 0.5, 1, 0.5, false);
+ zArm = BuilderProxy.proxy.newDrill(world, 0, 0, 0, 0.5, 0.5, 1, true);
+
+ head = BuilderProxy.proxy.newDrillHead(world, 0, 0, 0, 0.2, 1, 0.2);
+ head.shadowSize = 1.0F;
+
+ world.spawnEntityInWorld(xArm);
+ world.spawnEntityInWorld(yArm);
+ world.spawnEntityInWorld(zArm);
+ world.spawnEntityInWorld(head);
+ }
+
+ @Override
+ protected void entityInit() {}
+
+ @Override
+ protected void readEntityFromNBT(NBTTagCompound nbt) {
+ xRoot = nbt.getDouble("xRoot");
+ yRoot = nbt.getDouble("yRoot");
+ zRoot = nbt.getDouble("zRoot");
+ armSizeX = nbt.getDouble("armSizeX");
+ armSizeZ = nbt.getDouble("armSizeZ");
+ setArmSize(armSizeX, armSizeZ);
+ updatePosition();
+ }
+
+ @Override
+ protected void writeEntityToNBT(NBTTagCompound nbt) {
+ nbt.setDouble("xRoot", xRoot);
+ nbt.setDouble("yRoot", yRoot);
+ nbt.setDouble("zRoot", zRoot);
+ nbt.setDouble("armSizeX", armSizeX);
+ nbt.setDouble("armSizeZ", armSizeZ);
+ }
+
+ private void findAndJoinQuarry() {
+ TileEntity te = worldObj.getTileEntity((int) posX, (int) posY, (int) posZ);
+ if (te instanceof TileCEQuarry) {
+ parent = (TileCEQuarry) te;
+ parent.setArm(this);
+ } else {
+ setDead();
+ }
+ }
+
+ @Override
+ public void onUpdate() {
+ super.onUpdate();
+ updatePosition();
+
+ if (parent == null) {
+ findAndJoinQuarry();
+ }
+
+ if (parent == null) {
+ setDead();
+ }
+ }
+
+ public void updatePosition() {
+ double headPosX = headX / 32D;
+ double headPosY = headY / 32D;
+ double headPosZ = headZ / 32D;
+ xArm.setPosition(xRoot, yRoot, headPosZ + 0.25);
+ yArm.jSize = yRoot - headPosY - 1;
+ yArm.setPosition(headPosX + 0.25, headPosY + 1, headPosZ + 0.25);
+ zArm.setPosition(headPosX + 0.25, yRoot, zRoot);
+ head.setPosition(headPosX + 0.4, headPosY, headPosZ + 0.4);
+ }
+
+ @Override
+ public void setDead() {
+ if (worldObj != null && worldObj.isRemote) {
+ xArm.setDead();
+ yArm.setDead();
+ zArm.setDead();
+ head.setDead();
+ }
+
+ super.setDead();
+ }
+}
diff --git a/src/main/java/net/kanawo/cemodern/recipe/GateRecipe.java b/src/main/java/net/kanawo/cemodern/recipe/GateRecipe.java
new file mode 100644
index 0000000..c7129a1
--- /dev/null
+++ b/src/main/java/net/kanawo/cemodern/recipe/GateRecipe.java
@@ -0,0 +1,44 @@
+package net.kanawo.cemodern.recipe;
+
+import net.minecraft.inventory.InventoryCrafting;
+import net.minecraft.item.ItemStack;
+import net.minecraft.world.World;
+import net.minecraftforge.oredict.ShapedOreRecipe;
+
+import buildcraft.transport.gates.GateDefinition.GateLogic;
+import buildcraft.transport.gates.GateDefinition.GateMaterial;
+import buildcraft.transport.gates.ItemGate;
+
+/**
+ * A shaped recipe whose gates must be of one material and logic. Gates are told apart only by NBT, which
+ * {@link ShapedOreRecipe} ignores, so without this any gate would do. Expansions on the gate are allowed.
+ */
+public class GateRecipe extends ShapedOreRecipe {
+
+ private final GateMaterial material;
+ private final GateLogic logic;
+
+ /** The recipe arguments are those of {@link ShapedOreRecipe}; give the gate as {@code ItemGate.makeGateItem}. */
+ public GateRecipe(ItemStack result, GateMaterial material, GateLogic logic, Object... recipe) {
+ super(result, recipe);
+ this.material = material;
+ this.logic = logic;
+ }
+
+ @Override
+ public boolean matches(InventoryCrafting inv, World world) {
+ if (!super.matches(inv, world)) {
+ return false;
+ }
+
+ for (int i = 0; i < inv.getSizeInventory(); i++) {
+ ItemStack stack = inv.getStackInSlot(i);
+ if (stack != null && stack.getItem() instanceof ItemGate
+ && (ItemGate.getMaterial(stack) != material || ItemGate.getLogic(stack) != logic)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/net/kanawo/cemodern/tile/QuarryType.java b/src/main/java/net/kanawo/cemodern/tile/QuarryType.java
new file mode 100644
index 0000000..84f7567
--- /dev/null
+++ b/src/main/java/net/kanawo/cemodern/tile/QuarryType.java
@@ -0,0 +1,34 @@
+package net.kanawo.cemodern.tile;
+
+/** The three CE quarries. They share {@link TileCEQuarry} and differ only in how they treat fluids. */
+public enum QuarryType {
+
+ /** CEQ-2: a faster BuildCraft quarry with a bigger battery. Skips fluids like BuildCraft's does. */
+ FAST("quarry2", 1),
+ /** CEQ-3: also targets lava sources and removes them. */
+ LAVA("quarry3", 1),
+ /** CEQ-4: targets any fluid and turns fluids next to the drill into glass before digging. */
+ FLUID("quarry4", 5);
+
+ /** Block registry name, also the texture folder name. */
+ public final String name;
+ /** How many times BuildCraft's quarry input rate this quarry accepts per tick. */
+ final int receiveMultiplier;
+
+ QuarryType(String name, int receiveMultiplier) {
+ this.name = name;
+ this.receiveMultiplier = receiveMultiplier;
+ }
+
+ public TileCEQuarry createTile() {
+ switch (this) {
+ case LAVA:
+ return new TileCEQuarry.Lava();
+ case FLUID:
+ return new TileCEQuarry.Fluid();
+ case FAST:
+ default:
+ return new TileCEQuarry.Fast();
+ }
+ }
+}
diff --git a/src/main/java/net/kanawo/cemodern/tile/TileCEQuarry.java b/src/main/java/net/kanawo/cemodern/tile/TileCEQuarry.java
new file mode 100644
index 0000000..3cf9656
--- /dev/null
+++ b/src/main/java/net/kanawo/cemodern/tile/TileCEQuarry.java
@@ -0,0 +1,890 @@
+package net.kanawo.cemodern.tile;
+
+import java.util.List;
+
+import net.kanawo.cemodern.CEConfig;
+import net.kanawo.cemodern.entity.EntityCEQuarryArm;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockLiquid;
+import net.minecraft.block.material.Material;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.item.EntityItem;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.inventory.ISidedInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.MathHelper;
+import net.minecraftforge.common.util.ForgeDirection;
+import net.minecraftforge.fluids.IFluidBlock;
+
+import buildcraft.BuildCraftBuilders;
+import buildcraft.BuildCraftCore;
+import buildcraft.api.blueprints.BuilderAPI;
+import buildcraft.api.core.BuildCraftAPI;
+import buildcraft.api.core.IAreaProvider;
+import buildcraft.api.core.SafeTimeTracker;
+import buildcraft.api.filler.FillerManager;
+import buildcraft.api.statements.IStatementParameter;
+import buildcraft.api.tiles.IControllable;
+import buildcraft.api.tiles.IHasWork;
+import buildcraft.api.transport.IPipeConnection;
+import buildcraft.api.transport.IPipeTile;
+import buildcraft.core.Box;
+import buildcraft.core.Box.Kind;
+import buildcraft.core.CoreConstants;
+import buildcraft.core.DefaultProps;
+import buildcraft.core.blueprints.Blueprint;
+import buildcraft.core.blueprints.BptBuilderBase;
+import buildcraft.core.blueprints.BptBuilderBlueprint;
+import buildcraft.core.builders.TileAbstractBuilder;
+import buildcraft.core.builders.patterns.FillerPattern;
+import buildcraft.core.internal.IDropControlInventory;
+import buildcraft.core.lib.RFBattery;
+import buildcraft.core.lib.utils.BlockMiner;
+import buildcraft.core.lib.utils.BlockUtils;
+import buildcraft.core.lib.utils.Utils;
+import buildcraft.core.proxy.CoreProxy;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * The CE quarries, a port of CE's TileQuarry2 and TileQuarry4 for BuildCraft 1.2.5.
+ *
+ * It works like BuildCraft's {@code TileQuarry}: it builds a frame, then moves a mechanical arm over the area and
+ * mines blocks with BuildCraft's {@link BlockMiner}. That class keeps its state private, so this one cannot extend it
+ * and follows it instead. What CE changed:
+ *
+ *
+ */
+public abstract class TileCEQuarry extends TileAbstractBuilder
+ implements IHasWork, ISidedInventory, IDropControlInventory, IPipeConnection, IControllable {
+
+ /** Tiles registered separately per type, so a quarry keeps its type when loaded from NBT. */
+ public static class Fast extends TileCEQuarry {
+
+ public Fast() {
+ super(QuarryType.FAST);
+ }
+ }
+
+ public static class Lava extends TileCEQuarry {
+
+ public Lava() {
+ super(QuarryType.LAVA);
+ }
+ }
+
+ public static class Fluid extends TileCEQuarry {
+
+ public Fluid() {
+ super(QuarryType.FLUID);
+ }
+ }
+
+ private enum Stage {
+ BUILDING,
+ DIGGING,
+ MOVING,
+ IDLE,
+ DONE
+ }
+
+ private enum ScanResult {
+ FOUND,
+ NONE,
+ PENDING
+ }
+
+ /** Blocks looked at per tick while searching, so an empty area does not stall a tick. */
+ private static final int SCAN_BUDGET = 4096;
+ /** RF to remove a lava source (CE: 100 MJ). */
+ private static final int LAVA_ERASE_ENERGY = 1000;
+ /** RF to turn one fluid block into glass (CE: 200 MJ). */
+ private static final int FLUID_REPLACE_ENERGY = 2000;
+
+ public final QuarryType type;
+
+ public EntityCEQuarryArm arm;
+
+ private final Box box = new Box();
+ private int targetX, targetY, targetZ;
+ private double headPosX, headPosY, headPosZ;
+ private double speed = 0.03;
+ private Stage stage = Stage.BUILDING;
+ private boolean movingHorizontally;
+ private boolean movingVertically;
+ private float headTrajectory;
+ /** True while the arm returns to its rest position after the last target. */
+ private boolean parking;
+
+ /**
+ * Next block to look at: a layer and an index into that layer's serpentine order. {@link Integer#MAX_VALUE}
+ * means start again from the top.
+ */
+ private int scanY = Integer.MAX_VALUE;
+ private int scanIndex;
+
+ /** Whether the placer was sneaking, which mirrors the default area. */
+ private boolean mirrored;
+
+ private final SafeTimeTracker updateTracker = new SafeTimeTracker(BuildCraftCore.updateFactor);
+
+ private BptBuilderBase builder;
+ private boolean frameProducer = true;
+ private NBTTagCompound initNBT = null;
+ private BlockMiner miner;
+
+ protected TileCEQuarry(QuarryType type) {
+ this.type = type;
+ box.kind = Kind.STRIPES;
+ setBattery(
+ new RFBattery(
+ (int) (4 * 64 * BuilderAPI.BREAK_ENERGY * BuildCraftCore.miningMultiplier),
+ (int) (1000 * type.receiveMultiplier * BuildCraftCore.miningMultiplier),
+ 0));
+ }
+
+ @Override
+ public void onBlockPlacedBy(EntityLivingBase entity, ItemStack stack) {
+ super.onBlockPlacedBy(entity, stack);
+ mirrored = entity.isSneaking();
+ }
+
+ private void createUtilsIfNeeded() {
+ if (!worldObj.isRemote && builder == null) {
+ if (!box.isInitialized()) {
+ setBoundaries();
+ }
+
+ initializeBlueprintBuilder();
+ }
+
+ if (stage != Stage.BUILDING) {
+ box.isVisible = false;
+
+ if (arm == null) {
+ createArm();
+ }
+
+ if (!worldObj.isRemote
+ && (headPosX < box.xMin || headPosX > box.xMax || headPosZ < box.zMin || headPosZ > box.zMax)) {
+ setHead(box.xMin + 1, yCoord + 2, box.zMin + 1);
+ }
+ } else {
+ box.isVisible = true;
+ }
+ }
+
+ private void createArm() {
+ worldObj.spawnEntityInWorld(
+ new EntityCEQuarryArm(
+ worldObj,
+ box.xMin + CoreConstants.PIPE_MAX_POS,
+ yCoord + box.sizeY() - 1 + CoreConstants.PIPE_MIN_POS,
+ box.zMin + CoreConstants.PIPE_MAX_POS,
+ box.sizeX() - 2 + CoreConstants.PIPE_MIN_POS * 2,
+ box.sizeZ() - 2 + CoreConstants.PIPE_MIN_POS * 2,
+ this));
+ }
+
+ /** Callback from the arm once it is created. */
+ public void setArm(EntityCEQuarryArm arm) {
+ this.arm = arm;
+ }
+
+ /** The quarry does not load chunks, so it waits until every chunk of its area is loaded. */
+ private boolean areChunksLoaded() {
+ for (int chunkX = box.xMin >> 4; chunkX <= box.xMax >> 4; chunkX++) {
+ for (int chunkZ = box.zMin >> 4; chunkZ <= box.zMax >> 4; chunkZ++) {
+ if (!worldObj.blockExists(chunkX << 4, box.yMax, chunkZ << 4)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void updateEntity() {
+ super.updateEntity();
+
+ if (worldObj.isRemote) {
+ if (stage != Stage.DONE) {
+ moveHead(speed);
+ }
+
+ return;
+ }
+
+ if (stage == Stage.DONE) {
+ if (mode == Mode.Loop) {
+ resetScan();
+ stage = Stage.IDLE;
+ } else {
+ return;
+ }
+ }
+
+ if (!areChunksLoaded()) {
+ return;
+ }
+
+ if (mode == Mode.Off && stage != Stage.MOVING) {
+ return;
+ }
+
+ createUtilsIfNeeded();
+
+ if (stage == Stage.BUILDING) {
+ if (builder != null && !builder.isDone(this)) {
+ builder.buildNextSlot(worldObj, this, xCoord, yCoord, zCoord);
+ } else {
+ stage = Stage.IDLE;
+ }
+ } else if (stage == Stage.DIGGING) {
+ dig();
+ } else if (stage == Stage.IDLE) {
+ // idling() sends its own network update when the stage changes.
+ idling();
+ return;
+ } else if (stage == Stage.MOVING) {
+ int energyUsed = getBattery()
+ .useEnergy(20, (int) Math.ceil(20D + (double) getBattery().getEnergyStored() / 10), false);
+
+ if (energyUsed >= 20) {
+ speed = 0.1 + energyUsed / 2000F;
+ moveHead(speed);
+ } else {
+ speed = 0;
+ }
+ }
+
+ if (updateTracker.markTimeIfDelay(worldObj)) {
+ sendNetworkUpdate();
+ }
+ }
+
+ private void dig() {
+ if (miner == null) {
+ stage = Stage.IDLE;
+ return;
+ }
+
+ int rfTaken = miner.acceptEnergy(getBattery().getEnergyStored());
+ getBattery().useEnergy(rfTaken, rfTaken, false);
+
+ // BlockMiner also reports hasMined() when the break event was cancelled, so check hasFailed() first.
+ if (miner.hasMined() && !miner.hasFailed()) {
+ // Collect items dropped around the head, such as the contents of a mined chest.
+ AxisAlignedBB around = AxisAlignedBB
+ .getBoundingBox(headPosX - 2, headPosY - 2, headPosZ - 2, headPosX + 3, headPosY + 3, headPosZ + 3);
+ @SuppressWarnings("unchecked")
+ List