Add EMC Builder: a BuildCraft Builder that pays for materials with EMC
- TileEMCBuilder extends TileBuilder. During build() it exposes virtual material slots backed by EMC, then charges the EMC value (1:1) of what was used. Real items and tank fluids are still used first. - EMC is stored per player per world (EmcPool, WorldSavedData), so all EMC Builders a player owns in a world share one balance. - GUI based on BuildCraft's Builder GUI, with an EMC consume slot like the Transmutation Table's and the owner's balance shown. - Blueprint schematic strips the owner; the first player to open an unowned builder becomes its owner. - Lit top while building is not drawn. - Shapeless recipe: Builder + Transmutation Table. - Depend on local BuildCraft 7.1.27 and FMProjectE dev jars in libs/ (not committed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
536e567348
commit
870e5d13eb
18 files changed
+999
-2
No files matched your search
@@ -1,8 +1,22 @@
|
||||
package net.kanawo.emcbuilder;
|
||||
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
|
||||
import buildcraft.core.render.RenderBuilder;
|
||||
import cpw.mods.fml.client.registry.ClientRegistry;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
|
||||
public class ClientProxy extends CommonProxy {
|
||||
|
||||
// Override CommonProxy methods here, if you want a different behaviour on the client (e.g. registering renders).
|
||||
// Don't forget to call the super methods as well.
|
||||
|
||||
@Override
|
||||
public void init(FMLInitializationEvent event) {
|
||||
super.init(event);
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,25 @@
|
||||
package net.kanawo.emcbuilder;
|
||||
|
||||
import net.kanawo.emcbuilder.block.BlockEMCBuilder;
|
||||
import net.kanawo.emcbuilder.block.SchematicEMCBuilder;
|
||||
import net.kanawo.emcbuilder.gui.GuiHandler;
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import buildcraft.BuildCraftBuilders;
|
||||
import buildcraft.api.blueprints.BuilderAPI;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStartingEvent;
|
||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import moze_intel.projecte.gameObjs.ObjHandler;
|
||||
|
||||
public class CommonProxy {
|
||||
|
||||
public static BlockEMCBuilder emcBuilderBlock;
|
||||
|
||||
// preInit "Run before anything else. Read your config, create blocks, items, etc, and register them with the
|
||||
// GameRegistry." (Remove if not needed)
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
@@ -14,10 +27,23 @@ public class CommonProxy {
|
||||
|
||||
EMCBuilder.LOG.info(Config.greeting);
|
||||
EMCBuilder.LOG.info("I am EMCBuilder at version " + Tags.VERSION);
|
||||
|
||||
emcBuilderBlock = new BlockEMCBuilder();
|
||||
GameRegistry.registerBlock(emcBuilderBlock, "emcBuilder");
|
||||
GameRegistry.registerTileEntity(TileEMCBuilder.class, EMCBuilder.MODID + ":EMCBuilder");
|
||||
}
|
||||
|
||||
// load "Do your mod setup. Build whatever data structures you care about. Register recipes." (Remove if not needed)
|
||||
public void init(FMLInitializationEvent event) {}
|
||||
public void init(FMLInitializationEvent event) {
|
||||
NetworkRegistry.INSTANCE.registerGuiHandler(EMCBuilder.instance, new GuiHandler());
|
||||
|
||||
BuilderAPI.schematicRegistry.registerSchematicBlock(emcBuilderBlock, SchematicEMCBuilder.class);
|
||||
|
||||
GameRegistry.addShapelessRecipe(
|
||||
new ItemStack(emcBuilderBlock),
|
||||
BuildCraftBuilders.builderBlock,
|
||||
ObjHandler.transmuteStone);
|
||||
}
|
||||
|
||||
// postInit "Handle interaction with other mods, complete your setup based on this." (Remove if not needed)
|
||||
public void postInit(FMLPostInitializationEvent event) {}
|
||||
|
||||
@@ -10,12 +10,20 @@ import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStartingEvent;
|
||||
|
||||
@Mod(modid = EMCBuilder.MODID, version = "1.0.0", name = "EMCBuilder", acceptedMinecraftVersions = "[1.7.10]")
|
||||
@Mod(
|
||||
modid = EMCBuilder.MODID,
|
||||
version = "1.0.0",
|
||||
name = "EMCBuilder",
|
||||
acceptedMinecraftVersions = "[1.7.10]",
|
||||
dependencies = "required-after:BuildCraft|Builders;required-after:ProjectE")
|
||||
public class EMCBuilder {
|
||||
|
||||
public static final String MODID = "emcbuilder";
|
||||
public static final Logger LOG = LogManager.getLogger(MODID);
|
||||
|
||||
@Mod.Instance(MODID)
|
||||
public static EMCBuilder instance;
|
||||
|
||||
@SidedProxy(clientSide = "net.kanawo.emcbuilder.ClientProxy", serverSide = "net.kanawo.emcbuilder.CommonProxy")
|
||||
public static CommonProxy proxy;
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package net.kanawo.emcbuilder.block;
|
||||
|
||||
import net.kanawo.emcbuilder.EMCBuilder;
|
||||
import net.kanawo.emcbuilder.gui.GuiHandler;
|
||||
import net.kanawo.emcbuilder.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;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
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;
|
||||
|
||||
public class BlockEMCBuilder extends BlockBuilder {
|
||||
|
||||
private static final String TEXTURE_PREFIX = EMCBuilder.MODID + ":emcbuilderBlock";
|
||||
|
||||
public BlockEMCBuilder() {
|
||||
super();
|
||||
setBlockName("emcBuilder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int metadata) {
|
||||
return new TileEMCBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as BlockBuilder, but opens the EMC Builder GUI. BlockBuilder's version cannot be called because it opens
|
||||
* BuildCraft's own Builder GUI.
|
||||
*/
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX,
|
||||
float hitY, float hitZ) {
|
||||
BlockInteractionEvent event = new BlockInteractionEvent(player, this);
|
||||
FMLCommonHandler.instance()
|
||||
.bus()
|
||||
.post(event);
|
||||
if (event.isCanceled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.isSneaking()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TileEntity tile = world.getTileEntity(x, y, z);
|
||||
TileEMCBuilder builder = tile instanceof TileEMCBuilder ? (TileEMCBuilder) tile : null;
|
||||
|
||||
Item equipped = player.getCurrentEquippedItem() != null ? player.getCurrentEquippedItem()
|
||||
.getItem() : null;
|
||||
if (equipped instanceof ItemConstructionMarker) {
|
||||
if (ItemConstructionMarker.linkStarted(player.getCurrentEquippedItem())) {
|
||||
ItemConstructionMarker.link(player.getCurrentEquippedItem(), world, x, y, z);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean filledTank = builder != null
|
||||
&& TankUtils.handleRightClick(builder, ForgeDirection.UNKNOWN, player, true, false);
|
||||
if (!filledTank && !world.isRemote) {
|
||||
player.openGui(EMCBuilder.instance, GuiHandler.EMC_BUILDER, world, x, y, z);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Textures are looked up as textures/blocks/emcbuilderBlock/{top,bottom,front,side,...}.png. */
|
||||
@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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.kanawo.emcbuilder.block;
|
||||
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
|
||||
import buildcraft.builders.schematics.SchematicBuilderLike;
|
||||
|
||||
/**
|
||||
* Blueprint schematic that, like the Builder's, drops the build state, and also drops the owner, so a copy built by
|
||||
* someone else does not draw on the original owner's EMC.
|
||||
*/
|
||||
public class SchematicEMCBuilder extends SchematicBuilderLike {
|
||||
|
||||
@Override
|
||||
public void onNBTLoaded() {
|
||||
super.onNBTLoaded();
|
||||
|
||||
if (tileNBT != null) {
|
||||
tileNBT.removeTag(TileEMCBuilder.OWNER_MOST);
|
||||
tileNBT.removeTag(TileEMCBuilder.OWNER_LEAST);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package net.kanawo.emcbuilder.gui;
|
||||
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import buildcraft.builders.gui.ContainerBuilder;
|
||||
import buildcraft.core.lib.gui.widgets.ScrollbarWidget;
|
||||
|
||||
/**
|
||||
* The Builder container plus an EMC consume slot. Extending {@link ContainerBuilder} keeps BuildCraft's requirement
|
||||
* tooltips and GUI watcher handling.
|
||||
*/
|
||||
public class ContainerEMCBuilder extends ContainerBuilder {
|
||||
|
||||
/** Matches the slot frame at (132, 26) in emcbuilder.png. */
|
||||
public static final int CONSUME_SLOT_X = 133;
|
||||
public static final int CONSUME_SLOT_Y = 27;
|
||||
|
||||
private static final int PLAYER_SLOTS = 9 * 4;
|
||||
|
||||
/** Index of the consume slot; the builder and player slots are all before it. */
|
||||
private final int consumeSlot;
|
||||
|
||||
public ContainerEMCBuilder(IInventory playerInventory, TileEMCBuilder builder) {
|
||||
super(playerInventory, builder);
|
||||
|
||||
// A builder made from a blueprint has no owner yet; whoever opens it first takes it.
|
||||
if (!builder.getWorldObj().isRemote && playerInventory instanceof InventoryPlayer) {
|
||||
builder.claimOwner(((InventoryPlayer) playerInventory).player);
|
||||
}
|
||||
|
||||
consumeSlot = inventorySlots.size();
|
||||
addSlotToContainer(new SlotEMCConsume(builder, CONSUME_SLOT_X, CONSUME_SLOT_Y));
|
||||
}
|
||||
|
||||
public ScrollbarWidget getScrollbar() {
|
||||
return scrollbarWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same behaviour as BuildCraftContainer, which assumes the player inventory is the last 36 slots; the consume slot
|
||||
* comes after it here. Shift-clicking never moves items into the consume slot.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack transferStackInSlot(EntityPlayer player, int slotIndex) {
|
||||
if (slotIndex == consumeSlot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Slot slot = (Slot) inventorySlots.get(slotIndex);
|
||||
|
||||
if (slot == null || !slot.getHasStack()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int playerStart = consumeSlot - PLAYER_SLOTS;
|
||||
int hotbarStart = consumeSlot - 9;
|
||||
ItemStack stack = slot.getStack();
|
||||
ItemStack original = stack.copy();
|
||||
|
||||
if (slotIndex >= playerStart) {
|
||||
if (!shiftIntoBuilder(stack, playerStart)) {
|
||||
boolean fromHotbar = slotIndex >= hotbarStart;
|
||||
|
||||
if (!shiftItemStack(
|
||||
stack,
|
||||
fromHotbar ? playerStart : hotbarStart,
|
||||
fromHotbar ? hotbarStart : consumeSlot)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else if (!shiftItemStack(stack, playerStart, consumeSlot)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
slot.onSlotChange(stack, original);
|
||||
|
||||
if (stack.stackSize <= 0) {
|
||||
slot.putStack(null);
|
||||
} else {
|
||||
slot.onSlotChanged();
|
||||
}
|
||||
|
||||
if (stack.stackSize == original.stackSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
slot.onPickupFromSlot(player, stack);
|
||||
return original;
|
||||
}
|
||||
|
||||
private boolean shiftIntoBuilder(ItemStack stack, int builderSlots) {
|
||||
for (int i = 0; i < builderSlots; i++) {
|
||||
Slot slot = (Slot) inventorySlots.get(i);
|
||||
|
||||
if (slot.isItemValid(stack) && shiftItemStack(stack, i, i + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
package net.kanawo.emcbuilder.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.kanawo.emcbuilder.EMCBuilder;
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import buildcraft.BuildCraftCore;
|
||||
import buildcraft.builders.gui.SlotBuilderRequirement;
|
||||
import buildcraft.core.blueprints.RequirementItemStack;
|
||||
import buildcraft.core.lib.fluids.Tank;
|
||||
import buildcraft.core.lib.gui.AdvancedSlot;
|
||||
import buildcraft.core.lib.gui.GuiAdvancedInterface;
|
||||
import buildcraft.core.lib.network.command.CommandWriter;
|
||||
import buildcraft.core.lib.network.command.PacketCommand;
|
||||
import buildcraft.core.lib.utils.StringUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import moze_intel.projecte.utils.Constants;
|
||||
|
||||
/**
|
||||
* BuildCraft's GuiBuilder with the EMC consume slot and the stored EMC added. GuiBuilder cannot be extended because it
|
||||
* creates its own ContainerBuilder.
|
||||
*/
|
||||
public class GuiEMCBuilder extends GuiAdvancedInterface {
|
||||
|
||||
/** BuildCraft's builder.png with the EMC consume slot added. */
|
||||
private static final ResourceLocation REGULAR_TEXTURE = new ResourceLocation(
|
||||
EMCBuilder.MODID,
|
||||
"textures/gui/emcbuilder.png");
|
||||
private static final ResourceLocation BLUEPRINT_TEXTURE = new ResourceLocation(
|
||||
"buildcraftbuilders:textures/gui/builder_blueprint.png");
|
||||
|
||||
private final TileEMCBuilder builder;
|
||||
private GuiButton selectedButton;
|
||||
|
||||
public GuiEMCBuilder(IInventory playerInventory, TileEMCBuilder builder) {
|
||||
super(new ContainerEMCBuilder(playerInventory, builder), builder, BLUEPRINT_TEXTURE);
|
||||
this.builder = builder;
|
||||
xSize = 256;
|
||||
ySize = 225;
|
||||
|
||||
resetNullSlots(6 * 4);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
slots.set(i * 4 + j, new SlotBuilderRequirement(this, 179 + j * 18, 18 + i * 18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContainerEMCBuilder getContainerBuilder() {
|
||||
return (ContainerEMCBuilder) getContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawGuiContainerForegroundLayer(int par1, int par2) {
|
||||
super.drawGuiContainerForegroundLayer(par1, par2);
|
||||
|
||||
drawCenteredString(StringUtils.localize("tile.emcBuilder.name"), 178 / 2, 16, 0x404040);
|
||||
|
||||
drawCenteredString(
|
||||
StatCollector.translateToLocalFormatted(
|
||||
"gui.emcbuilder.stored",
|
||||
Constants.EMC_FORMATTER.format(builder.getStoredEmc())),
|
||||
178 / 2,
|
||||
51,
|
||||
0x404040);
|
||||
|
||||
if (builder.getStackInSlot(0) != null) {
|
||||
fontRendererObj.drawString(StringUtils.localize("gui.building.resources"), 8, 60, 0x404040);
|
||||
fontRendererObj.drawString(StringUtils.localize("gui.inventory"), 8, ySize - 97, 0x404040);
|
||||
fontRendererObj.drawString(StringUtils.localize("gui.needed"), 178, 7, 0x404040);
|
||||
fontRendererObj.drawString(StringUtils.localize("gui.building.fluids"), 178, 133, 0x404040);
|
||||
}
|
||||
|
||||
drawTooltips(par1, par2);
|
||||
}
|
||||
|
||||
private void drawTooltips(int par1, int par2) {
|
||||
int top = guiTop + 145;
|
||||
for (int i = 0; i < builder.fluidTanks.length; i++) {
|
||||
int left = guiLeft + 179 + 18 * i;
|
||||
if (par1 >= left && par2 >= top && par1 < (left + 16) && par2 < (left + 47)) {
|
||||
List<String> fluidTip = new ArrayList<>();
|
||||
Tank tank = builder.fluidTanks[i];
|
||||
if (tank.getFluid() != null && tank.getFluid().amount > 0) {
|
||||
fluidTip.add(
|
||||
tank.getFluid()
|
||||
.getLocalizedName());
|
||||
if (!BuildCraftCore.hideFluidNumbers) {
|
||||
fluidTip.add(
|
||||
EnumChatFormatting.GRAY + "" + EnumChatFormatting.ITALIC + tank.getFluid().amount + " mB");
|
||||
}
|
||||
} else {
|
||||
fluidTip.add(StatCollector.translateToLocal("gui.fluidtank.empty"));
|
||||
}
|
||||
drawHoveringText(fluidTip, par1 - guiLeft, par2 - guiTop, fontRendererObj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
drawTooltipForSlotAt(par1, par2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void drawGuiContainerBackgroundLayer(float f, int x, int y) {
|
||||
// Like GuiBuilder, super is not called because the GUI is resized dynamically.
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
boolean isBlueprint = builder.getStackInSlot(0) != null;
|
||||
|
||||
mc.renderEngine.bindTexture(REGULAR_TEXTURE);
|
||||
drawTexturedModalRect(guiLeft, guiTop, 0, 0, 176, ySize);
|
||||
mc.renderEngine.bindTexture(BLUEPRINT_TEXTURE);
|
||||
if (isBlueprint) {
|
||||
drawTexturedModalRect(guiLeft + 169, guiTop, 169, 0, 256 - 169, ySize);
|
||||
}
|
||||
|
||||
List<RequirementItemStack> needs = builder.getNeededItems();
|
||||
|
||||
if (needs != null) {
|
||||
if (needs.size() > slots.size()) {
|
||||
getContainerBuilder().getScrollbar().hidden = false;
|
||||
getContainerBuilder().getScrollbar()
|
||||
.setLength((needs.size() - slots.size() + 3) / 4);
|
||||
} else {
|
||||
getContainerBuilder().getScrollbar().hidden = true;
|
||||
}
|
||||
|
||||
int offset = getContainerBuilder().getScrollbar()
|
||||
.getPosition() * 4;
|
||||
for (int s = 0; s < slots.size(); s++) {
|
||||
int ts = offset + s;
|
||||
if (ts >= needs.size()) {
|
||||
((SlotBuilderRequirement) slots.get(s)).stack = null;
|
||||
} else {
|
||||
((SlotBuilderRequirement) slots.get(s)).stack = needs.get(ts);
|
||||
}
|
||||
}
|
||||
|
||||
for (GuiButton b : (List<GuiButton>) buttonList) {
|
||||
b.visible = true;
|
||||
}
|
||||
} else {
|
||||
getContainerBuilder().getScrollbar().hidden = true;
|
||||
for (AdvancedSlot slot : slots) {
|
||||
((SlotBuilderRequirement) slot).stack = null;
|
||||
}
|
||||
for (GuiButton b : (List<GuiButton>) buttonList) {
|
||||
b.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
drawWidgets(x, y);
|
||||
|
||||
if (isBlueprint) {
|
||||
drawBackgroundSlots(x, y);
|
||||
|
||||
for (int i = 0; i < builder.fluidTanks.length; i++) {
|
||||
Tank tank = builder.fluidTanks[i];
|
||||
if (tank.getFluid() != null && tank.getFluid().amount > 0) {
|
||||
drawFluid(tank.getFluid(), guiLeft + 179 + 18 * i, guiTop + 145, 16, 47, tank.getCapacity());
|
||||
}
|
||||
}
|
||||
|
||||
mc.renderEngine.bindTexture(BLUEPRINT_TEXTURE);
|
||||
|
||||
for (int i = 0; i < builder.fluidTanks.length; i++) {
|
||||
Tank tank = builder.fluidTanks[i];
|
||||
if (tank.getFluid() != null && tank.getFluid().amount > 0) {
|
||||
drawTexturedModalRect(guiLeft + 179 + 18 * i, guiTop + 145, 0, 54, 16, 47);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
buttonList.add(new EraseTankButton(i, guiLeft + 178 + 18 * i, guiTop + 197, 18, 18));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseMovedOrUp(int mouseX, int mouseY, int eventType) {
|
||||
super.mouseMovedOrUp(mouseX, mouseY, eventType);
|
||||
if (this.selectedButton != null && eventType == 0) {
|
||||
this.selectedButton.mouseReleased(mouseX, mouseY);
|
||||
this.selectedButton = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Empties one of the builder's fluid tanks; same as GuiBuilder's erase button. */
|
||||
private class EraseTankButton extends GuiButton {
|
||||
|
||||
private boolean clicked;
|
||||
|
||||
public EraseTankButton(int id, int x, int y, int width, int height) {
|
||||
super(id, x, y, width, height, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int x, int y) {
|
||||
if (super.mousePressed(mc, x, y)) {
|
||||
selectedButton = this;
|
||||
clicked = true;
|
||||
BuildCraftCore.instance.sendToServer(new PacketCommand(builder, "eraseFluidTank", new CommandWriter() {
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf data) {
|
||||
data.writeInt(id);
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int x, int y) {
|
||||
super.mouseReleased(x, y);
|
||||
clicked = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft mc, int x, int y) {
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
// hovered
|
||||
this.field_146123_n = x >= this.xPosition && y >= this.yPosition
|
||||
&& x < this.xPosition + this.width
|
||||
&& y < this.yPosition + this.height;
|
||||
|
||||
mc.renderEngine.bindTexture(BLUEPRINT_TEXTURE);
|
||||
drawTexturedModalRect(xPosition, yPosition, 0, (clicked ? 1 : this.field_146123_n ? 2 : 0) * 18, 18, 18);
|
||||
mouseDragged(mc, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.kanawo.emcbuilder.gui;
|
||||
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import cpw.mods.fml.common.network.IGuiHandler;
|
||||
|
||||
public class GuiHandler implements IGuiHandler {
|
||||
|
||||
public static final int EMC_BUILDER = 0;
|
||||
|
||||
@Override
|
||||
public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) {
|
||||
TileEMCBuilder builder = getBuilder(id, world, x, y, z);
|
||||
return builder == null ? null : new ContainerEMCBuilder(player.inventory, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) {
|
||||
TileEMCBuilder builder = getBuilder(id, world, x, y, z);
|
||||
return builder == null ? null : new GuiEMCBuilder(player.inventory, builder);
|
||||
}
|
||||
|
||||
private static TileEMCBuilder getBuilder(int id, World world, int x, int y, int z) {
|
||||
if (id != EMC_BUILDER || !world.blockExists(x, y, z)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TileEntity tile = world.getTileEntity(x, y, z);
|
||||
return tile instanceof TileEMCBuilder ? (TileEMCBuilder) tile : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.kanawo.emcbuilder.gui;
|
||||
|
||||
import net.kanawo.emcbuilder.tile.TileEMCBuilder;
|
||||
import net.minecraft.inventory.InventoryBasic;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import moze_intel.projecte.utils.EMCHelper;
|
||||
|
||||
/**
|
||||
* Converts any item with an EMC value into EMC stored in the builder, like the Transmutation Table's consume slot.
|
||||
* The slot never holds anything itself.
|
||||
*/
|
||||
public class SlotEMCConsume extends Slot {
|
||||
|
||||
private final TileEMCBuilder builder;
|
||||
|
||||
public SlotEMCConsume(TileEMCBuilder builder, int x, int y) {
|
||||
super(new InventoryBasic("EMC", false, 1), 0, x, y);
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(ItemStack stack) {
|
||||
return stack != null && EMCHelper.doesItemHaveEmc(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(ItemStack stack) {
|
||||
if (stack == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The client discards the stack too, so it does not show an item the server never stored.
|
||||
if (!builder.getWorldObj().isRemote) {
|
||||
builder.consumeForEmc(stack);
|
||||
}
|
||||
|
||||
onSlotChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package net.kanawo.emcbuilder.tile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldSavedData;
|
||||
import net.minecraft.world.storage.MapStorage;
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
|
||||
/**
|
||||
* EMC stored for EMC Builders, one balance per player, saved with the world (data/emcbuilder_emc.dat). All
|
||||
* dimensions of a world share the same storage, so every EMC Builder a player owns in the world draws from the same
|
||||
* balance. Server side only.
|
||||
*/
|
||||
public class EmcPool extends WorldSavedData {
|
||||
|
||||
private static final String NAME = "emcbuilder_emc";
|
||||
private static final double MAX_EMC = moze_intel.projecte.utils.Constants.TILE_MAX_EMC;
|
||||
|
||||
private final Map<UUID, Double> balances = new HashMap<>();
|
||||
|
||||
public EmcPool(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static EmcPool get(World world) {
|
||||
MapStorage storage = world.mapStorage;
|
||||
EmcPool pool = (EmcPool) storage.loadData(EmcPool.class, NAME);
|
||||
|
||||
if (pool == null) {
|
||||
pool = new EmcPool(NAME);
|
||||
storage.setData(NAME, pool);
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
public double get(UUID player) {
|
||||
Double emc = balances.get(player);
|
||||
return emc == null ? 0 : emc;
|
||||
}
|
||||
|
||||
/** Adds (or, with a negative amount, removes) EMC, keeping the balance between 0 and the maximum. */
|
||||
public void add(UUID player, double amount) {
|
||||
double emc = Math.min(MAX_EMC, Math.max(0, get(player) + amount));
|
||||
|
||||
if (emc == 0) {
|
||||
balances.remove(player);
|
||||
} else {
|
||||
balances.put(player, emc);
|
||||
}
|
||||
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound nbt) {
|
||||
balances.clear();
|
||||
NBTTagList list = nbt.getTagList("Players", Constants.NBT.TAG_COMPOUND);
|
||||
|
||||
for (int i = 0; i < list.tagCount(); i++) {
|
||||
NBTTagCompound entry = list.getCompoundTagAt(i);
|
||||
balances.put(
|
||||
new UUID(entry.getLong("UUIDMost"), entry.getLong("UUIDLeast")),
|
||||
Math.min(MAX_EMC, Math.max(0, entry.getDouble("EMC"))));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound nbt) {
|
||||
NBTTagList list = new NBTTagList();
|
||||
|
||||
for (Map.Entry<UUID, Double> balance : balances.entrySet()) {
|
||||
NBTTagCompound entry = new NBTTagCompound();
|
||||
entry.setLong(
|
||||
"UUIDMost",
|
||||
balance.getKey()
|
||||
.getMostSignificantBits());
|
||||
entry.setLong(
|
||||
"UUIDLeast",
|
||||
balance.getKey()
|
||||
.getLeastSignificantBits());
|
||||
entry.setDouble("EMC", balance.getValue());
|
||||
list.appendTag(entry);
|
||||
}
|
||||
|
||||
nbt.setTag("Players", list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
package net.kanawo.emcbuilder.tile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import buildcraft.builders.TileBuilder;
|
||||
import buildcraft.core.blueprints.BptBuilderBase;
|
||||
import buildcraft.core.blueprints.BptBuilderBlueprint;
|
||||
import buildcraft.core.blueprints.RequirementItemStack;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import moze_intel.projecte.utils.EMCHelper;
|
||||
|
||||
/**
|
||||
* A Builder that pays for building materials with EMC.
|
||||
* <p>
|
||||
* The EMC is not stored in the tile but in its owner's balance in {@link EmcPool}, so all EMC Builders a player owns
|
||||
* in a world share it. The owner is the player who placed the builder, or for one built from a blueprint, the first
|
||||
* player who opens it.
|
||||
* <p>
|
||||
* BuildCraft only builds blocks whose materials are present in the builder's inventory, and consumes them by
|
||||
* shrinking the stacks it finds there. While {@link #build()} runs, this tile therefore appends virtual slots after
|
||||
* the real inventory, one per needed item that has an EMC value, sized to what the stored EMC can afford. After the
|
||||
* build step the amount taken from each virtual slot is charged at 1 EMC per EMC value. Real items in the material
|
||||
* slots come first in the inventory, so they are used before EMC.
|
||||
* <p>
|
||||
* Outside {@link #build()} the virtual slots are hidden, so GUIs, hoppers, pipes and robots only ever see the real
|
||||
* inventory.
|
||||
*/
|
||||
public class TileEMCBuilder extends TileBuilder {
|
||||
|
||||
/** NBT keys of the owner's UUID; SchematicEMCBuilder removes them from blueprints. */
|
||||
public static final String OWNER_MOST = "OwnerUUIDMost";
|
||||
public static final String OWNER_LEAST = "OwnerUUIDLeast";
|
||||
|
||||
private static final int EMC_SYNC_INTERVAL = 10;
|
||||
|
||||
private UUID owner;
|
||||
|
||||
/** Owner's balance as last received from the server. Client side only. */
|
||||
private double clientEmc;
|
||||
/** Owner's balance as last sent to clients. Server side only. */
|
||||
private double sentEmc = -1;
|
||||
private int ticksSinceEmcSync;
|
||||
|
||||
private final List<EmcSlot> emcSlots = new ArrayList<>();
|
||||
private boolean emcSlotsExposed;
|
||||
|
||||
/** A virtual material slot backed by stored EMC. */
|
||||
private static final class EmcSlot {
|
||||
|
||||
final long emcPerItem;
|
||||
final int initialSize;
|
||||
ItemStack stack;
|
||||
|
||||
EmcSlot(ItemStack stack, long emcPerItem) {
|
||||
this.stack = stack;
|
||||
this.emcPerItem = emcPerItem;
|
||||
this.initialSize = stack.stackSize;
|
||||
}
|
||||
|
||||
int consumed() {
|
||||
return stack == null ? initialSize : initialSize - stack.stackSize;
|
||||
}
|
||||
}
|
||||
|
||||
/** The owner's EMC balance; on the client, as last synced. */
|
||||
public double getStoredEmc() {
|
||||
if (worldObj.isRemote) {
|
||||
return clientEmc;
|
||||
}
|
||||
|
||||
return owner == null ? 0
|
||||
: EmcPool.get(worldObj)
|
||||
.get(owner);
|
||||
}
|
||||
|
||||
/** Makes the player the owner if the builder has none yet. Server side only. */
|
||||
public void claimOwner(EntityPlayer player) {
|
||||
if (owner == null) {
|
||||
owner = player.getUniqueID();
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockPlacedBy(EntityLivingBase entity, ItemStack stack) {
|
||||
super.onBlockPlacedBy(entity, stack);
|
||||
|
||||
if (entity instanceof EntityPlayer) {
|
||||
owner = entity.getUniqueID();
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts the whole stack into EMC for the owner. Server side only. */
|
||||
public void consumeForEmc(ItemStack stack) {
|
||||
long value = EMCHelper.getEmcValue(stack);
|
||||
|
||||
if (owner == null || value <= 0 || stack.stackSize <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
EmcPool.get(worldObj)
|
||||
.add(owner, (double) value * stack.stackSize);
|
||||
stack.stackSize = 0;
|
||||
sendNetworkUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntity() {
|
||||
super.updateEntity();
|
||||
|
||||
if (worldObj.isRemote) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The balance can also change through the owner's other EMC Builders, so poll it.
|
||||
if (++ticksSinceEmcSync >= EMC_SYNC_INTERVAL) {
|
||||
ticksSinceEmcSync = 0;
|
||||
|
||||
if (getStoredEmc() != sentEmc) {
|
||||
sendNetworkUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
BptBuilderBase bpt = getBlueprint();
|
||||
double emc = getStoredEmc();
|
||||
|
||||
if (!(bpt instanceof BptBuilderBlueprint) || emc <= 0) {
|
||||
super.build();
|
||||
return;
|
||||
}
|
||||
|
||||
// The needed item list is only filled once the builder has been initialized.
|
||||
bpt.initialize();
|
||||
prepareEmcSlots(((BptBuilderBlueprint) bpt).getNeededItems(), emc);
|
||||
|
||||
emcSlotsExposed = true;
|
||||
|
||||
try {
|
||||
super.build();
|
||||
} finally {
|
||||
emcSlotsExposed = false;
|
||||
chargeEmcSlots();
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareEmcSlots(List<RequirementItemStack> needs, double emc) {
|
||||
emcSlots.clear();
|
||||
|
||||
if (needs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (RequirementItemStack need : needs) {
|
||||
if (need.stack == null || need.stack.getItem() == null || need.size <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long value = EMCHelper.getEmcValue(need.stack);
|
||||
|
||||
if (value <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int affordable = (int) Math.min(Integer.MAX_VALUE, Math.floor(emc / value));
|
||||
int size = Math.min(Math.min(need.stack.getMaxStackSize(), need.size), affordable);
|
||||
|
||||
if (size <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemStack stack = need.stack.copy();
|
||||
stack.stackSize = size;
|
||||
emcSlots.add(new EmcSlot(stack, value));
|
||||
}
|
||||
}
|
||||
|
||||
private void chargeEmcSlots() {
|
||||
double cost = 0;
|
||||
|
||||
for (EmcSlot slot : emcSlots) {
|
||||
cost += (double) slot.consumed() * slot.emcPerItem;
|
||||
}
|
||||
|
||||
emcSlots.clear();
|
||||
|
||||
if (cost > 0) {
|
||||
EmcPool.get(worldObj)
|
||||
.add(owner, -cost);
|
||||
}
|
||||
}
|
||||
|
||||
private int realSize() {
|
||||
return super.getSizeInventory();
|
||||
}
|
||||
|
||||
private EmcSlot emcSlot(int i) {
|
||||
return emcSlotsExposed && i >= realSize() ? emcSlots.get(i - realSize()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSizeInventory() {
|
||||
return emcSlotsExposed ? realSize() + emcSlots.size() : realSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int i) {
|
||||
EmcSlot slot = emcSlot(i);
|
||||
return slot != null ? slot.stack : super.getStackInSlot(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack decrStackSize(int i, int amount) {
|
||||
EmcSlot slot = emcSlot(i);
|
||||
|
||||
if (slot == null) {
|
||||
return super.decrStackSize(i, amount);
|
||||
}
|
||||
|
||||
if (slot.stack == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemStack taken = slot.stack.splitStack(Math.min(amount, slot.stack.stackSize));
|
||||
|
||||
if (slot.stack.stackSize <= 0) {
|
||||
slot.stack = null;
|
||||
}
|
||||
|
||||
return taken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents(int i, ItemStack stack) {
|
||||
EmcSlot slot = emcSlot(i);
|
||||
|
||||
if (slot == null) {
|
||||
super.setInventorySlotContents(i, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
// Schematic.useItem only writes to a slot once its stack is used up (possibly leaving a container item
|
||||
// behind). Either way the whole virtual stack has been consumed; container items are not kept.
|
||||
slot.stack = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlotOnClosing(int i) {
|
||||
return emcSlot(i) != null ? null : super.getStackInSlotOnClosing(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int i, ItemStack stack) {
|
||||
return emcSlot(i) == null && super.isItemValidForSlot(i, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound nbt) {
|
||||
super.readFromNBT(nbt);
|
||||
owner = nbt.hasKey(OWNER_MOST) ? new UUID(nbt.getLong(OWNER_MOST), nbt.getLong(OWNER_LEAST)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound nbt) {
|
||||
super.writeToNBT(nbt);
|
||||
|
||||
if (owner != null) {
|
||||
nbt.setLong(OWNER_MOST, owner.getMostSignificantBits());
|
||||
nbt.setLong(OWNER_LEAST, owner.getLeastSignificantBits());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(ByteBuf stream) {
|
||||
super.writeData(stream);
|
||||
sentEmc = getStoredEmc();
|
||||
stream.writeDouble(sentEmc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readData(ByteBuf stream) {
|
||||
super.readData(stream);
|
||||
clientEmc = stream.readDouble();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
tile.emcBuilder.name=EMC Builder
|
||||
gui.emcbuilder.stored=EMC: %s
|
||||
@@ -0,0 +1,2 @@
|
||||
tile.emcBuilder.name=EMCビルダー
|
||||
gui.emcbuilder.stored=EMC: %s
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Reference in new issue
Block a user