From 7899ce82f764e1de5c0bba1fd7afa03e5adc5a35 Mon Sep 17 00:00:00 2001 From: KoyoNoguchi Date: Tue, 27 Oct 2026 11:13:02 +0900 Subject: [PATCH] Add the CE quarries, a port of CE's improved BuildCraft quarries Port CE's three quarries from BuildCraft 3.1.5 (Minecraft 1.2.5) to BuildCraft 7.1. TileCEQuarry follows BuildCraft 7's TileQuarry, whose state is private, with CE's changes: - Twice the battery, so the arm moves faster. - A configurable default area (64x64), mirrored when placed while sneaking, and a configurable lowest Y level (5). - Lava no longer blocks the columns below it. - The search continues from the last target and moves past each one once done, so fluids flowing back in do not hold the arm in place. - No chunk loading. - CEQ-3 removes lava sources; CEQ-4 turns fluids around the drill into glass and accepts five times the input. Soft blocks are checked without BuildCraft's cache, which is stale in chunks without players. The arm is a copy of EntityMechanicalArm, which only works with BuildCraft's own quarry. The recipes keep CE's layout with BuildCraft 7 items; GateRecipe checks the gates' material and logic, which ShapedOreRecipe ignores. Textures come from CE. Also give the EMC Builder a default.png for its back, sides and bottom instead of substituting the bottom icon in code. Co-Authored-By: Claude Opus 5.5 --- README.md | 23 +- .../java/net/kanawo/cemodern/CEConfig.java | 53 ++ .../java/net/kanawo/cemodern/CEModern.java | 3 +- .../java/net/kanawo/cemodern/ClientProxy.java | 11 + .../java/net/kanawo/cemodern/CommonProxy.java | 92 ++ .../kanawo/cemodern/block/BlockCEQuarry.java | 111 +++ .../cemodern/block/BlockEMCBuilder.java | 20 +- .../cemodern/entity/EntityCEQuarryArm.java | 152 +++ .../kanawo/cemodern/recipe/GateRecipe.java | 44 + .../net/kanawo/cemodern/tile/QuarryType.java | 34 + .../kanawo/cemodern/tile/TileCEQuarry.java | 890 ++++++++++++++++++ .../resources/assets/cemodern/lang/en_US.lang | 3 + .../resources/assets/cemodern/lang/ja_JP.lang | 3 + .../emcbuilderBlock/{side.png => default.png} | Bin .../textures/blocks/quarry2/front.png | Bin 0 -> 641 bytes .../cemodern/textures/blocks/quarry2/side.png | Bin 0 -> 513 bytes .../cemodern/textures/blocks/quarry2/top.png | Bin 0 -> 615 bytes .../textures/blocks/quarry3/front.png | Bin 0 -> 615 bytes .../cemodern/textures/blocks/quarry3/side.png | Bin 0 -> 479 bytes .../cemodern/textures/blocks/quarry3/top.png | Bin 0 -> 606 bytes .../textures/blocks/quarry4/front.png | Bin 0 -> 666 bytes .../cemodern/textures/blocks/quarry4/side.png | Bin 0 -> 638 bytes .../cemodern/textures/blocks/quarry4/top.png | Bin 0 -> 771 bytes src/main/resources/mcmod.info | 6 +- 24 files changed, 1424 insertions(+), 21 deletions(-) create mode 100644 src/main/java/net/kanawo/cemodern/CEConfig.java create mode 100644 src/main/java/net/kanawo/cemodern/block/BlockCEQuarry.java create mode 100644 src/main/java/net/kanawo/cemodern/entity/EntityCEQuarryArm.java create mode 100644 src/main/java/net/kanawo/cemodern/recipe/GateRecipe.java create mode 100644 src/main/java/net/kanawo/cemodern/tile/QuarryType.java create mode 100644 src/main/java/net/kanawo/cemodern/tile/TileCEQuarry.java rename src/main/resources/assets/cemodern/textures/blocks/emcbuilderBlock/{side.png => default.png} (100%) create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry2/front.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry2/side.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry2/top.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry3/front.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry3/side.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry3/top.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry4/front.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry4/side.png create mode 100644 src/main/resources/assets/cemodern/textures/blocks/quarry4/top.png 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 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 getDrops(World world, int x, int y, int z, int metadata, int fortune) { + if (BuildCraftBuilders.quarryOneTimeUse) { + return new ArrayList(); + } + + return super.getDrops(world, x, y, z, metadata, fortune); + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int metadata) { + if (world.isRemote) { + return; + } + + BuildCraftBuilders.frameBlock.removeNeighboringFrames(world, x, y, z); + + super.breakBlock(world, x, y, z, block, metadata); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, + float hitY, float hitZ) { + if (super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ)) { + return true; + } + + if (player.isSneaking()) { + return false; + } + + // Restart the quarry if it is a wrench. + Item equipped = player.getCurrentEquippedItem() != null ? player.getCurrentEquippedItem() + .getItem() : null; + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TileCEQuarry && equipped instanceof IToolWrench + && ((IToolWrench) equipped).canWrench(player, x, y, z)) { + ((TileCEQuarry) tile).reinitialize(); + ((IToolWrench) equipped).wrenchUsed(player, x, y, z); + return true; + } + + return false; + } +} diff --git a/src/main/java/net/kanawo/cemodern/block/BlockEMCBuilder.java b/src/main/java/net/kanawo/cemodern/block/BlockEMCBuilder.java index 84d6e50..b18ffcb 100644 --- a/src/main/java/net/kanawo/cemodern/block/BlockEMCBuilder.java +++ b/src/main/java/net/kanawo/cemodern/block/BlockEMCBuilder.java @@ -3,7 +3,6 @@ package net.kanawo.cemodern.block; import net.kanawo.cemodern.CEModern; import net.kanawo.cemodern.gui.GuiHandler; import net.kanawo.cemodern.tile.TileEMCBuilder; -import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.tileentity.TileEntity; @@ -14,7 +13,6 @@ import buildcraft.api.events.BlockInteractionEvent; import buildcraft.builders.BlockBuilder; import buildcraft.builders.ItemConstructionMarker; import buildcraft.core.lib.fluids.TankUtils; -import buildcraft.core.lib.utils.ResourceUtils; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -74,23 +72,13 @@ public class BlockEMCBuilder extends BlockBuilder { return true; } - /** Textures are looked up as textures/blocks/emcbuilderBlock/{top,bottom,front,side,...}.png. */ + /** + * Textures are looked up as textures/blocks/emcbuilderBlock/{top,front,default}.png. default.png covers the faces + * without a texture of their own: the back, the left, the right and the bottom. + */ @Override @SideOnly(Side.CLIENT) public String[] getIconBlockNames() { return new String[] { TEXTURE_PREFIX }; } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister register) { - super.registerBlockIcons(register); - - // Without bottom.png BlockBuildCraft would fall back to a missing "default" texture. Use the left face - // (index 4), which resolves to side.png, instead. - String bottom = TEXTURE_PREFIX + "/bottom"; - if (!ResourceUtils.resourceExists(ResourceUtils.iconToResourcePath(register, bottom))) { - icons[0][0] = icons[0][4]; - } - } } diff --git a/src/main/java/net/kanawo/cemodern/entity/EntityCEQuarryArm.java b/src/main/java/net/kanawo/cemodern/entity/EntityCEQuarryArm.java new file mode 100644 index 0000000..4dce847 --- /dev/null +++ b/src/main/java/net/kanawo/cemodern/entity/EntityCEQuarryArm.java @@ -0,0 +1,152 @@ +package net.kanawo.cemodern.entity; + +import net.kanawo.cemodern.tile.TileCEQuarry; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import buildcraft.builders.BuilderProxy; +import buildcraft.core.lib.EntityBlock; + +/** + * The mechanical arm of a CE quarry, the same as BuildCraft's {@code EntityMechanicalArm}, which only works with + * BuildCraft's own quarry tile. + *

+ * 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 items = worldObj.getEntitiesWithinAABB(EntityItem.class, around); + for (EntityItem entity : items) { + if (entity.isDead) { + continue; + } + + ItemStack mineable = entity.getEntityItem(); + if (mineable.stackSize <= 0) { + continue; + } + + CoreProxy.proxy.removeEntity(entity); + miner.mineStack(mineable); + } + } + + if (miner.hasMined() || miner.hasFailed()) { + miner = null; + scanIndex++; + + if (!findFrame()) { + initializeBlueprintBuilder(); + } else { + stage = Stage.IDLE; + } + } + } + + /** Whether the frame next to the quarry is still there. If not, the quarry rebuilds it. */ + private boolean findFrame() { + for (int i = 2; i < 6; i++) { + ForgeDirection o = ForgeDirection.getOrientation(i); + if (box.contains(xCoord + o.offsetX, yCoord + o.offsetY, zCoord + o.offsetZ)) { + return worldObj.getBlock(xCoord + o.offsetX, yCoord + o.offsetY, zCoord + o.offsetZ) + == BuildCraftBuilders.frameBlock; + } + } + + return true; + } + + private void idling() { + ScanResult result = parking ? ScanResult.NONE : findTarget(); + + if (result == ScanResult.PENDING) { + return; + } + + if (result == ScanResult.FOUND) { + stage = Stage.MOVING; + } else { + int restX = box.xMin + 1, restY = yCoord + 2, restZ = box.zMin + 1; + + if (headPosX == restX && headPosY == restY && headPosZ == restZ) { + parking = false; + stage = Stage.DONE; + } else { + setTarget(restX, restY, restZ); + parking = true; + stage = Stage.MOVING; + } + } + + movingHorizontally = true; + movingVertically = true; + headTrajectory = (float) Math.atan2(targetZ - headPosZ, targetX - headPosX); + sendNetworkUpdate(); + } + + private void resetScan() { + scanY = Integer.MAX_VALUE; + scanIndex = 0; + } + + /** + * Looks for the next block to dig, from the top layer down to {@link CEConfig#quarryMinY}. Each layer is walked + * in a serpentine order that starts where the layer above ended, and the search continues from where the last one + * stopped. If something is found, it becomes the target, and the search moves past it once the arm is done with it + * (see {@link #positionReached} and {@link #dig}). Each block is visited once per pass, so a fluid flowing back in + * behind the arm does not hold it in place. + */ + private ScanResult findTarget() { + int sizeX = box.sizeX() - 2; + int sizeZ = box.sizeZ() - 2; + int perLayer = sizeX * sizeZ; + int minY = Math.max(CEConfig.quarryMinY, 0); + int budget = SCAN_BUDGET; + + if (scanY > yCoord + 3) { + scanY = yCoord + 3; + scanIndex = 0; + } + + for (; scanY >= minY; scanY--, scanIndex = 0) { + for (; scanIndex < perLayer; scanIndex++) { + if (budget-- <= 0) { + return ScanResult.PENDING; + } + + int row = scanIndex / sizeZ; + int column = scanIndex % sizeZ; + int searchX = (scanY & 1) == 0 ? row : sizeX - 1 - row; + int searchZ = (searchX & 1) == (scanY & 1) ? column : sizeZ - 1 - column; + int x = box.xMin + 1 + searchX; + int z = box.zMin + 1 + searchZ; + + if (isTarget(x, scanY, z)) { + setTarget(x, scanY + 1, z); + return ScanResult.FOUND; + } + } + } + + return ScanResult.NONE; + } + + private boolean isTarget(int x, int y, int z) { + Block block = worldObj.getBlock(x, y, z); + return isFluidTarget(block, worldObj.getBlockMetadata(x, y, z)) || isMineable(block, x, y, z); + } + + private boolean isMineable(Block block, int x, int y, int z) { + return BlockUtils.canChangeBlock(block, worldObj, x, y, z) && !isSoft(block, x, y, z) + && !isFluid(block) + && block != BuildCraftBuilders.frameBlock; + } + + /** + * Same as {@link BuildCraftAPI#isSoftBlock}, without its cache. The cache is only updated when the block change is + * sent to players, so in a chunk without players a mined block would still read as solid. + */ + private boolean isSoft(Block block, int x, int y, int z) { + return block.isAir(worldObj, x, y, z) || BuildCraftAPI.softBlocks.contains(block) + || block.isReplaceable(worldObj, x, y, z); + } + + /** Fluids this quarry goes to even though it cannot mine them. */ + private boolean isFluidTarget(Block block, int meta) { + switch (type) { + case LAVA: + return block instanceof BlockLiquid && block.getMaterial() == Material.lava && meta == 0; + case FLUID: + return isFluid(block); + case FAST: + default: + return false; + } + } + + private static boolean isFluid(Block block) { + return block instanceof BlockLiquid || block instanceof IFluidBlock; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + + if (nbt.hasKey("box")) { + box.initialize(nbt.getCompoundTag("box")); + } + + targetX = nbt.getInteger("targetX"); + targetY = nbt.getInteger("targetY"); + targetZ = nbt.getInteger("targetZ"); + headPosX = nbt.getDouble("headPosX"); + headPosY = nbt.getDouble("headPosY"); + headPosZ = nbt.getDouble("headPosZ"); + + if (nbt.hasKey("scanY")) { + scanY = nbt.getInteger("scanY"); + scanIndex = nbt.getInteger("scanIndex"); + } + + parking = nbt.getBoolean("parking"); + + // The build state is loaded in initialize(), once the frame blueprint exists. + initNBT = (NBTTagCompound) nbt.getCompoundTag("bpt") + .copy(); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + + nbt.setInteger("targetX", targetX); + nbt.setInteger("targetY", targetY); + nbt.setInteger("targetZ", targetZ); + nbt.setDouble("headPosX", headPosX); + nbt.setDouble("headPosY", headPosY); + nbt.setDouble("headPosZ", headPosZ); + nbt.setInteger("scanY", scanY); + nbt.setInteger("scanIndex", scanIndex); + nbt.setBoolean("parking", parking); + + NBTTagCompound boxTag = new NBTTagCompound(); + box.writeToNBT(boxTag); + nbt.setTag("box", boxTag); + + NBTTagCompound bptNBT = new NBTTagCompound(); + + if (builder != null) { + NBTTagCompound builderCpt = new NBTTagCompound(); + builder.saveBuildStateToNBT(builderCpt, this); + bptNBT.setTag("builderState", builderCpt); + } + + nbt.setTag("bpt", bptNBT); + } + + /** Called by {@link #moveHead} when the arm arrives at its target. */ + private void positionReached() { + if (worldObj.isRemote) { + return; + } + + if (parking) { + parking = false; + stage = Stage.DONE; + return; + } + + int x = targetX; + int y = targetY - 1; + int z = targetZ; + + if (type == QuarryType.FLUID) { + // The target itself becomes glass and is then mined. Its neighbours stay glass, walling off the shaft. + replaceFluid(x, y, z); + replaceFluid(x + 1, y, z); + replaceFluid(x - 1, y, z); + replaceFluid(x, y, z + 1); + replaceFluid(x, y, z - 1); + replaceFluid(x, y + 1, z); + } + + Block block = worldObj.getBlock(x, y, z); + + if (type == QuarryType.LAVA && isFluidTarget(block, worldObj.getBlockMetadata(x, y, z))) { + worldObj.setBlockToAir(x, y, z); + useFluidEnergy(LAVA_ERASE_ENERGY); + scanIndex++; + stage = Stage.IDLE; + } else if (isMineable(block, x, y, z)) { + // dig() moves the search on once the block is mined. + miner = new BlockMiner(worldObj, this, x, y, z); + stage = Stage.DIGGING; + } else { + scanIndex++; + stage = Stage.IDLE; + } + } + + private void replaceFluid(int x, int y, int z) { + if (worldObj.blockExists(x, y, z) && isFluid(worldObj.getBlock(x, y, z))) { + worldObj.setBlock(x, y, z, Blocks.glass); + useFluidEnergy(FLUID_REPLACE_ENERGY); + } + } + + /** Takes what it can of the cost; like CE, a missing remainder does not stop the work. */ + private void useFluidEnergy(int energy) { + int cost = (int) (energy * BuildCraftCore.miningMultiplier); + getBattery().useEnergy(0, cost, false); + } + + @Override + protected int getNetworkUpdateRange() { + return DefaultProps.NETWORK_UPDATE_RANGE + + (int) Math.ceil(Math.sqrt(yCoord * yCoord + box.sizeX() * box.sizeX() + box.sizeZ() * box.sizeZ())); + } + + @Override + public void invalidate() { + super.invalidate(); + destroy(); + } + + @Override + public void onChunkUnload() { + destroy(); + } + + @Override + public void destroy() { + if (arm != null) { + arm.setDead(); + } + + arm = null; + + frameProducer = false; + + if (miner != null) { + miner.invalidate(); + } + } + + @Override + public boolean hasWork() { + return stage != Stage.DONE; + } + + /** + * Uses the marker next to the quarry if it spans at least 3x3, or else the default area from the config. The + * default area lies behind the quarry, with the quarry on its near edge. + */ + private void setBoundaries() { + IAreaProvider a = Utils.getNearbyAreaProvider(worldObj, xCoord, yCoord, zCoord); + + if (a != null && (a.xMax() - a.xMin() + 1 < 3 || a.zMax() - a.zMin() + 1 < 3)) { + a = null; + } + + if (a != null) { + box.initialize(a); + + if (box.sizeY() < 5) { + box.yMax = box.yMin + 4; + } + + a.removeFromWorld(); + } else { + int size = CEConfig.quarryDefaultSize; + int before = mirrored ? size - CEConfig.quarryDefaultPosition - 1 : CEConfig.quarryDefaultPosition; + int after = size - before - 1; + int far = size - 1; + int xMin, zMin; + + switch (worldObj.getBlockMetadata(xCoord, yCoord, zCoord) & 7) { + case 3: + xMin = xCoord - before; + zMin = zCoord - far - 1; + break; + case 4: + xMin = xCoord + 1; + zMin = zCoord - before; + break; + case 5: + xMin = xCoord - far - 1; + zMin = zCoord - after; + break; + case 2: + default: + xMin = xCoord - after; + zMin = zCoord + 1; + break; + } + + box.initialize(xMin, yCoord, zMin, xMin + far, yCoord + 4, zMin + far); + } + + sendNetworkUpdate(); + } + + /** Starts building the frame. Already placed frame blocks are kept. */ + private void initializeBlueprintBuilder() { + Blueprint bpt = ((FillerPattern) FillerManager.registry.getPattern("buildcraft:frame")) + .getBlueprint(box, worldObj, new IStatementParameter[0], BuildCraftBuilders.frameBlock, 0); + + if (bpt != null) { + builder = new BptBuilderBlueprint(bpt, worldObj, box.xMin, yCoord, box.zMin); + speed = 0; + stage = Stage.BUILDING; + sendNetworkUpdate(); + } + } + + @Override + public void writeData(ByteBuf stream) { + super.writeData(stream); + box.writeData(stream); + stream.writeInt(targetX); + stream.writeShort(targetY); + stream.writeInt(targetZ); + stream.writeDouble(headPosX); + stream.writeDouble(headPosY); + stream.writeDouble(headPosZ); + stream.writeFloat((float) speed); + stream.writeFloat(headTrajectory); + int flags = stage.ordinal(); + flags |= movingHorizontally ? 0x10 : 0; + flags |= movingVertically ? 0x20 : 0; + stream.writeByte(flags); + } + + @Override + public void readData(ByteBuf stream) { + super.readData(stream); + box.readData(stream); + targetX = stream.readInt(); + targetY = stream.readUnsignedShort(); + targetZ = stream.readInt(); + headPosX = stream.readDouble(); + headPosY = stream.readDouble(); + headPosZ = stream.readDouble(); + speed = stream.readFloat(); + headTrajectory = stream.readFloat(); + int flags = stream.readUnsignedByte(); + stage = Stage.values()[flags & 0x07]; + movingHorizontally = (flags & 0x10) != 0; + movingVertically = (flags & 0x20) != 0; + + createUtilsIfNeeded(); + + if (arm != null) { + arm.setHead(headPosX, headPosY, headPosZ); + arm.updatePosition(); + } + } + + @Override + public void initialize() { + super.initialize(); + + if (!worldObj.isRemote && !box.initialized) { + setBoundaries(); + } + + createUtilsIfNeeded(); + + if (initNBT != null && builder != null) { + builder.loadBuildStateToNBT(initNBT.getCompoundTag("builderState"), this); + } + + initNBT = null; + + sendNetworkUpdate(); + } + + /** Rebuilds the frame and searches the whole area again, also after the quarry has finished. */ + public void reinitialize() { + if (miner != null) { + miner.invalidate(); + miner = null; + } + + parking = false; + resetScan(); + initializeBlueprintBuilder(); + } + + // The inventory holds an endless supply of frames for building the frame, and nothing else. It is hidden from + // pipes and hoppers by the sided inventory methods below. + + @Override + public int getSizeInventory() { + return 1; + } + + @Override + public ItemStack getStackInSlot(int i) { + return frameProducer ? new ItemStack(BuildCraftBuilders.frameBlock) : null; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return frameProducer ? new ItemStack(BuildCraftBuilders.frameBlock, j) : null; + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) {} + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public String getInventoryName() { + return ""; + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 0; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return false; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return false; + } + + @Override + public void openInventory() {} + + @Override + public void closeInventory() {} + + @Override + public boolean isBuildingMaterialSlot(int i) { + return true; + } + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return new int[] {}; + } + + @Override + public boolean canInsertItem(int slot, ItemStack stack, int side) { + return false; + } + + @Override + public boolean canExtractItem(int slot, ItemStack stack, int side) { + return false; + } + + private void moveHead(double instantSpeed) { + if (movingHorizontally) { + if (Math.abs(targetX - headPosX) < instantSpeed * 2 && Math.abs(targetZ - headPosZ) < instantSpeed * 2) { + headPosX = targetX; + headPosZ = targetZ; + + movingHorizontally = false; + + if (!movingVertically) { + positionReached(); + headPosY = targetY; + } + } else { + headPosX += MathHelper.cos(headTrajectory) * instantSpeed; + headPosZ += MathHelper.sin(headTrajectory) * instantSpeed; + } + } + + if (movingVertically) { + if (Math.abs(targetY - headPosY) < instantSpeed * 2) { + headPosY = targetY; + + movingVertically = false; + + if (!movingHorizontally) { + positionReached(); + headPosX = targetX; + headPosZ = targetZ; + } + } else if (targetY > headPosY) { + headPosY += instantSpeed; + } else { + headPosY -= instantSpeed; + } + } + + if (arm != null && worldObj.isRemote) { + arm.setHead(headPosX, headPosY, headPosZ); + arm.updatePosition(); + } + } + + private void setHead(double x, double y, double z) { + headPosX = x; + headPosY = y; + headPosZ = z; + } + + private void setTarget(int x, int y, int z) { + targetX = x; + targetY = y; + targetZ = z; + } + + @Override + public AxisAlignedBB getRenderBoundingBox() { + return new Box(this).extendToEncompass(box) + .expand(50) + .getBoundingBox(); + } + + @Override + public Box getBox() { + return box; + } + + @Override + public boolean acceptsControlMode(Mode mode) { + return mode == Mode.Off || mode == Mode.On || mode == Mode.Loop; + } + + @Override + public boolean doDrop() { + return false; + } + + @Override + public ConnectOverride overridePipeConnection(IPipeTile.PipeType type, ForgeDirection with) { + return type == IPipeTile.PipeType.ITEM ? ConnectOverride.CONNECT : ConnectOverride.DEFAULT; + } +} diff --git a/src/main/resources/assets/cemodern/lang/en_US.lang b/src/main/resources/assets/cemodern/lang/en_US.lang index f9dc91e..50aa613 100644 --- a/src/main/resources/assets/cemodern/lang/en_US.lang +++ b/src/main/resources/assets/cemodern/lang/en_US.lang @@ -1,2 +1,5 @@ tile.emcBuilder.name=EMC Builder gui.cemodern.stored=EMC: %s +tile.ceQuarry2.name=Quarry of fast mining type +tile.ceQuarry3.name=Quarry of lava removal type +tile.ceQuarry4.name=Quarry of fluid replace type diff --git a/src/main/resources/assets/cemodern/lang/ja_JP.lang b/src/main/resources/assets/cemodern/lang/ja_JP.lang index 39f19ce..50ad678 100644 --- a/src/main/resources/assets/cemodern/lang/ja_JP.lang +++ b/src/main/resources/assets/cemodern/lang/ja_JP.lang @@ -1,2 +1,5 @@ tile.emcBuilder.name=EMCビルダー gui.cemodern.stored=EMC: %s +tile.ceQuarry2.name=採掘強化型クアーリー +tile.ceQuarry3.name=溶岩除去型クアーリー +tile.ceQuarry4.name=液体対策型クアーリー diff --git a/src/main/resources/assets/cemodern/textures/blocks/emcbuilderBlock/side.png b/src/main/resources/assets/cemodern/textures/blocks/emcbuilderBlock/default.png similarity index 100% rename from src/main/resources/assets/cemodern/textures/blocks/emcbuilderBlock/side.png rename to src/main/resources/assets/cemodern/textures/blocks/emcbuilderBlock/default.png diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry2/front.png b/src/main/resources/assets/cemodern/textures/blocks/quarry2/front.png new file mode 100644 index 0000000000000000000000000000000000000000..cc1fd0c111c327dddbf5a20b0d2560857144514b GIT binary patch literal 641 zcmV-{0)G98P)D8f}uUDzSXCz>Yn>k)lR3=@c=fP4FHbg0N}bV0G{Xh#>I<7A^@ybtAl*; zWQ#BC=OJXc+F3Lj1!QB7<}r&`FtKY0|nfm zn@*un0E{B4mWzuEz?_~M7i6o~$6_%6bm~fJA$$e&pq(|FO~80qtJMIQ&*y;gERje6 z#xwh7C7$Mq$KyW!{<{-9^lt2Ppw(&tCT5qHmjKl3bpWc>Dqwal42MGio}ZrqNTpH$ zWHK25Mxzk`#bObFWHJf-cUwNGJ0E~+$1t5v`)nzsmOvIihj91D?;VSP$Bf-ScJJ)gmkwi|s_aTW%0f}1u|xdHEM{I9SA<3*kW6o!*zM3&UG6r`cDwBWZnql%pB2tvl#$Q(*UsF?*VAr7J%t=TI_cmjYjoZ`a=EzZ`=KOlS0*}bG)oKO6@pvru=XdY-dojvHeFl6`)goUm zm%t-;&i5OCR4?+}FT!L(Kebbz0V5J=s@>e{w^%HSb#p30nelt>bKURtnt4B_|5>jA zbLMzDor-sn7`ezroEpeFkxcZ=y&2HItu?~GkbC|`?7E2cOQf2Nq( zdAph>QzA6i{*DZPPB+X-mRfLLOLfacc10Pp66Ss4b2N~uHfLHgkd-f0pIXU##-KvJ z7XRzkniJJ)txhD_)qKy>lDQt7`{)Vv88{pc!0^1vNNOY1otkhyE2@5Z`>xMGBFI~7 z*6{2Ji74yDAm`B|>N8-@jW8J*L>!3nK9CjCn!nra09dcr#lHFsm^)2m<}$}btpBr0 z>iTB0Db_!y68d0n&0+q7dB)5$|Fpba_m%Z6FkY}P2*^!y=2$uM00000NkvXXu0mjf DN<#cA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry2/top.png b/src/main/resources/assets/cemodern/textures/blocks/quarry2/top.png new file mode 100644 index 0000000000000000000000000000000000000000..0923f5786007d77a3cc3464d2b74f31fd3932f3f GIT binary patch literal 615 zcmV-t0+{`YP)0iy^0O#ehDq-I3S9Z`^A$;!YK<Mpc%KX-UBdrmjG~l zl$#ii^XGoQf9H3ijE)ui6wp2wMFxWb0F%kYSU)*6zrXqX27vD4=fL)CvQGi+yYS0f zpk)4VZ_n7@sOKh@Nge|)UVQ}M$Ff+B zW8%R&CS2DAAdX|e0tG4$aC}rRa(okf-^cfTvNR=2Qw}_j1J5IjBEl$QI8GRj6I|ED zbzR~(F4%88z`sI4QRk~vHo?{PHE=r%eyn?k@B09JySMZkYDNJlD9!%)&pTKN+jzF*lM={_u}_o`1VI3l%*9Tx*8^a=TpIiTzXIZOnPRJE zJ{=Q!5|U@_b73w%w{9YGh+002ovPDHLkV1gCz BB8LC~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry3/front.png b/src/main/resources/assets/cemodern/textures/blocks/quarry3/front.png new file mode 100644 index 0000000000000000000000000000000000000000..3ecb074502c08eaace2920e0e3aff387f245db57 GIT binary patch literal 615 zcmV-t0+{`YP)I#xwuSoOA4SyImK+bzJ})#{nRfN^uEx-RX1!Ae~N!=Jj5( zwWs;ZU-^&7$TJ(!bUJ<24_B*IAPEd8V!`HWJRV*&O0x1_jd#nQ8nR1`$qf> zs2U%>KLF7C(gR?m^d5`p#}1ow?;EUwmCktp#VU?-v^-CYyyGj!hAjlV7Xj|^h%`?0E@)}fO5GE zKt7)j>BrB2t2x|S z1XVp441k~(lzVxsKF{THAw!Q5nJ$PrYm(Ci%B4JNwORn|_j@3SL{LPV&Bim}GiBGw z?rygW$wG2&#TwXCP>~5Xr-GQWOxnL_%TQv@g1^@_0OwzW_=*4k002ovPDHLkV1nDM B6j%TN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry3/side.png b/src/main/resources/assets/cemodern/textures/blocks/quarry3/side.png new file mode 100644 index 0000000000000000000000000000000000000000..b58ac921f3ef6dbab80e5086475c88b7a0c0fc4a GIT binary patch literal 479 zcmV<50U-W~P)~r4zzSs57=X3Dh1(i|k$j~;Kuh(k;ZnxXZbwcJc&G#=B zznoR3z5@M8{!V5qQ<=NYRz}RKB`#T@VJm9=lv%UhE$vk$+6C&+6v$yhA$P@Atsi7wRiuC%xE{ruU1ff5^Tw+__9-CD1)8xJega_nF#+J>ybZu? zp0~&2@ssOB867M3DWH8WicF_d0KVMZ7~_}M=KAQ{djR?`Ujxmz$vy?N@3yxefQosy z+coC5+j$HmNge}N@4f$Ji?9fKeM;P&ngfES(zRGD(O+Zp@Ya|`M+l~}Gb zomQfEd`g<)v4&qgDlVlMj(heH4(2Y?LHa3>g7W|2 s&+I-NN(GvHFAQ}wOTR!fx4tU=3Fmb93R&#QU;qFB07*qoM6N<$g4FLFU;qFB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry4/front.png b/src/main/resources/assets/cemodern/textures/blocks/quarry4/front.png new file mode 100644 index 0000000000000000000000000000000000000000..79e5c53370f084e6f7c834b514694184b71db8a2 GIT binary patch literal 666 zcmV;L0%iS)P)2ba5&5%*yGmgH2{%F z#PeSLvhDTs{_t1+Bck%mj;Pn`{nHQUaycLf3@Bp3&Q+ySIXKaA9szK6mIvVW_RE9p z^Ybeph#GkJ{SyF}&t7^4JpSka@cc;ufV=z80JK^y0362~sc_sj46IfwAP5X-pEjPp z0QNmne+JaJczXfBdgHANM>ViTd8-Ag=5cdV2KF^jt+oNUzV-4uP9~E8G@DHTip3(}dM*qG0{}*&k!M~yod#ey90HKZWB^Dc z5}x_~GhnMTl}Z6_?(EyLp!0k@9s^J)n93+7y4^0|GSTn%0mx>vfLm{TXCPFo)i&U& zT6aBZLAjU5+UN0j+_TUwB5M~MJ8Oco3zSQFR4SDKSS%KR8;PKZrqiieV9S&}PV3I+ zbB`?q=T@wSeF`cv!Op25rfeqdzi6AGz?=m?0iXCGRkLW*n*aa+07*qoM6N<$g8Gv% Av;Y7A literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry4/side.png b/src/main/resources/assets/cemodern/textures/blocks/quarry4/side.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b1767b5a5887014fac1551e5090d54256f5841 GIT binary patch literal 638 zcmV-^0)hRBP)zqW$T|D~5T>T7a;#nXIG?~q2z;>QGBcAV%#emlV?W=3n&wy7lj|CU^Wfc=zd+!kP*d6x(VkZgi zbMNDxzn%@g?@V~5)H*W02M{|+P`~#(oEY&w?p>}bX5{Owynk{xqWOFdZ2QXly8BMz zcRexV_2cQ@h}@U%qsQ{TDl0+=e7wB;@5et}TpXT(FIQLG{r<{}mv^O6k|s$)k|Y#G zK~WUsc}||^=y{f9WLXy1X_}IzY1H@q5CS2D7z5pJpBM~&F&f=)dipAku!)!OpxJwr z@nlFB7!2M4*Fcxi=!R!UoBiNir#L4j)&p*GR*Sn7UTX#bLv+?McRQ*GG1$}*c1h?OTf5*4+8wZVn_vhzvUe)CO Y0A|L0k7uRFW&i*H07*qoM6N<$f@aw|IsgCw literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/cemodern/textures/blocks/quarry4/top.png b/src/main/resources/assets/cemodern/textures/blocks/quarry4/top.png new file mode 100644 index 0000000000000000000000000000000000000000..2123a6ebe20946f6a5654e2d59d56c1053268982 GIT binary patch literal 771 zcmV+e1N{7nP)>}s57Q)-7013 zQi)2HC=kvY$zI*rV7#kZKJ_Eoo45jV+e(wD&SODwm z>xIZSH#ZB7zjFZqjYfYD*mioqUa{wSx$~H&8T=L@83qyyux&7muZ1V_eP8i`X`0Gq z7)Giulm!e*ejixzMxz0Xi!YS{2M57|;{7)#pV>R?0Q(&!0_9q)y;C4iG6JI6giO?)N-V?s-BgcU?DHKw7r%?(P<-V{n*~Q2MpJ zPzuj@9>(i+#_M%_&%^gTs?{phYLy$u;l^>;JM6M|*u}CeEX%@m-LQJN!vl|j&;$B; zm1GliuCD>8jE*Y(|E{ipKnZ}8voipml*>Srl()CH%KUwug2#ZBl~l5FJ?V5Mo{o(H z@b}^Zh?F=zJq6vTFwdun=GA^-Lx zh}iireyS2fQJ~#!D`Z*Z0G8~ze8uWtG6LNb`j?Qjb=l`<8kywqzzSpT}+&S_q3wQ{$TCKv*{09gs6S^M&uWJAR002ovPDHLkV1ghD BXNLd) literal 0 HcmV?d00001 diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index eeca212..d2125be 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -3,7 +3,7 @@ "modList": [{ "modid": "${modId}", "name": "${modName}", - "description": "A Minecraft 1.7.10 port of CE. Adds the EMC Builder, a BuildCraft Builder that pays for its materials with EMC.", + "description": "A Minecraft 1.7.10 port of CE. Adds the EMC Builder, a BuildCraft Builder that pays for its materials with EMC, and the CE quarries, improved BuildCraft quarries.", "version": "${modVersion}", "mcversion": "${minecraftVersion}", "url": "", @@ -13,8 +13,8 @@ "logoFile": "", "screenshots": [], "parent": "", - "requiredMods": ["BuildCraft|Builders", "ProjectE"], - "dependencies": ["BuildCraft|Builders", "ProjectE"], + "requiredMods": ["BuildCraft|Builders", "BuildCraft|Factory", "BuildCraft|Silicon", "BuildCraft|Transport", "ProjectE"], + "dependencies": ["BuildCraft|Builders", "BuildCraft|Factory", "BuildCraft|Silicon", "BuildCraft|Transport", "ProjectE"], "dependants": [], "useDependencyInformation": false }]