From bd66140b54e08ffb98b538300e8851b5cbf708ba Mon Sep 17 00:00:00 2001 From: Boblet Date: Tue, 3 May 2022 15:45:00 +0200 Subject: [PATCH] GUI fluid identifier --- src/main/java/com/hbm/handler/GUIHandler.java | 2 + .../com/hbm/inventory/gui/GUIScreenFluid.java | 174 ++++++++++++++++++ .../com/hbm/items/IItemControlReceiver.java | 9 + src/main/java/com/hbm/items/ModItems.java | 4 + .../hbm/items/machine/ItemFluidIDMulti.java | 142 ++++++++++++++ .../com/hbm/packet/NBTItemControlPacket.java | 79 ++++++++ .../java/com/hbm/packet/PacketDispatcher.java | 2 + src/main/resources/assets/hbm/lang/de_DE.lang | 3 + src/main/resources/assets/hbm/lang/en_US.lang | 3 + .../assets/hbm/textures/gui/gui_planner.png | Bin 1751 -> 1759 bytes .../hbm/textures/gui/machine/gui_fluid.png | Bin 0 -> 1288 bytes .../textures/items/fluid_identifier_multi.png | Bin 0 -> 284 bytes 12 files changed, 418 insertions(+) create mode 100644 src/main/java/com/hbm/inventory/gui/GUIScreenFluid.java create mode 100644 src/main/java/com/hbm/items/IItemControlReceiver.java create mode 100644 src/main/java/com/hbm/items/machine/ItemFluidIDMulti.java create mode 100644 src/main/java/com/hbm/packet/NBTItemControlPacket.java create mode 100644 src/main/resources/assets/hbm/textures/gui/machine/gui_fluid.png create mode 100644 src/main/resources/assets/hbm/textures/items/fluid_identifier_multi.png diff --git a/src/main/java/com/hbm/handler/GUIHandler.java b/src/main/java/com/hbm/handler/GUIHandler.java index 0df9f040f..b8f6f4198 100644 --- a/src/main/java/com/hbm/handler/GUIHandler.java +++ b/src/main/java/com/hbm/handler/GUIHandler.java @@ -1723,6 +1723,8 @@ public class GUIHandler implements IGuiHandler { return new GUIScreenBobble((TileEntityBobble) world.getTileEntity(x, y, z)); case ModItems.guiID_item_holo_image: return new GUIScreenHolotape(); + case ModItems.guiID_item_fluid: + return new GUIScreenFluid(player); } return null; } diff --git a/src/main/java/com/hbm/inventory/gui/GUIScreenFluid.java b/src/main/java/com/hbm/inventory/gui/GUIScreenFluid.java new file mode 100644 index 000000000..f8193a0eb --- /dev/null +++ b/src/main/java/com/hbm/inventory/gui/GUIScreenFluid.java @@ -0,0 +1,174 @@ +package com.hbm.inventory.gui; + +import java.awt.Color; +import java.util.Arrays; + +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import com.hbm.inventory.fluid.FluidType; +import com.hbm.inventory.fluid.Fluids; +import com.hbm.items.ModItems; +import com.hbm.items.machine.ItemFluidIDMulti; +import com.hbm.lib.RefStrings; +import com.hbm.packet.NBTItemControlPacket; +import com.hbm.packet.PacketDispatcher; +import com.hbm.util.I18nUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; + +public class GUIScreenFluid extends GuiScreen { + + protected static final ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/machine/gui_fluid.png"); + protected int xSize = 176; + protected int ySize = 178; + protected int guiLeft; + protected int guiTop; + private GuiTextField search; + + private final EntityPlayer player; + private FluidType primary = Fluids.NONE; + private FluidType secondary = Fluids.NONE; + private FluidType[] searchArray = new FluidType[9]; + + public GUIScreenFluid(EntityPlayer player) { + this.player = player; + + Keyboard.enableRepeatEvents(true); + this.search = new GuiTextField(this.fontRendererObj, guiLeft + 46, guiTop + 10, 86, 12); + this.search.setTextColor(-1); + this.search.setDisabledTextColour(-1); + this.search.setEnableBackgroundDrawing(false); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float f) { + this.drawDefaultBackground(); + this.drawGuiContainerBackgroundLayer(f, mouseX, mouseY); + GL11.glDisable(GL11.GL_LIGHTING); + this.drawGuiContainerForegroundLayer(mouseX, mouseY); + GL11.glEnable(GL11.GL_LIGHTING); + } + + @Override + public void updateScreen() { + if(player.getHeldItem() == null || player.getHeldItem().getItem() != ModItems.fluid_identifier_multi) + player.closeScreen(); + } + + @Override + public void initGui() { + super.initGui(); + this.guiLeft = (this.width - this.xSize) / 2; + this.guiTop = (this.height - this.ySize) / 2; + + if(player.getHeldItem() != null && player.getHeldItem().getItem() == ModItems.fluid_identifier_multi) { + this.primary = ItemFluidIDMulti.getType(player.getHeldItem(), true); + this.secondary = ItemFluidIDMulti.getType(player.getHeldItem(), false); + } + } + + @Override + protected void mouseClicked(int i, int j, int button) { + + for(int k = 0; k < this.searchArray.length; k++) { + + if(this.searchArray[k] == null) + return; + + if(7 + k * 18 <= i && 7 + k * 18 + 18 > i && 29 < j && 29 + 18 >= j) { + if(button == 0) { + this.primary = this.searchArray[k]; + NBTTagCompound data = new NBTTagCompound(); + data.setInteger("primary", this.primary.getID()); + PacketDispatcher.wrapper.sendToServer(new NBTItemControlPacket(data)); + } else if(button == 1) { + this.secondary = this.searchArray[k]; + NBTTagCompound data = new NBTTagCompound(); + data.setInteger("secondary", this.secondary.getID()); + PacketDispatcher.wrapper.sendToServer(new NBTItemControlPacket(data)); + } + } + } + } + + protected void drawGuiContainerForegroundLayer(int i, int j) { + this.search.drawTextBox(); + + for(int k = 0; k < this.searchArray.length; k++) { + + if(this.searchArray[k] == null) + return; + + if(7 + k * 18 <= i && 7 + k * 18 + 18 > i && 29 < j && 29 + 18 >= j) + func_146283_a(Arrays.asList(new String[] { I18nUtil.resolveKey(this.searchArray[k].getUnlocalizedName()) }), i, j); + } + } + + protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(texture); + drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + if(this.search.isFocused()) + drawTexturedModalRect(guiLeft + 43, guiTop + 7, 166, 54, 90, 18); + + for(int k = 0; k < this.searchArray.length; k++) { + FluidType type = this.searchArray[k]; + + if(type == null) + return; + + Color color = new Color(type.getColor()); + GL11.glColor3f(color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F); + drawTexturedModalRect(guiLeft + 12 + k * 18, guiTop + 30, 12 + k * 18, 56, 8, 14); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + if(type == this.primary && type == this.secondary) { + drawTexturedModalRect(guiLeft + 7 + k * 18, guiTop + 29, 176, 36, 18, 18); + } else if(type == this.primary) { + drawTexturedModalRect(guiLeft + 7 + k * 18, guiTop + 29, 176, 0, 18, 18); + } else if(type == this.secondary) { + drawTexturedModalRect(guiLeft + 7 + k * 18, guiTop + 29, 176, 18, 18, 18); + } + } + } + + @Override + protected void keyTyped(char c, int key) { + + if(this.search.textboxKeyTyped(c, key)) { + updateSearch(); + } else { + super.keyTyped(c, key); + } + + if(key == 1 || key == this.mc.gameSettings.keyBindInventory.getKeyCode()) { + this.mc.thePlayer.closeScreen(); + } + } + + private void updateSearch() { + this.searchArray = new FluidType[9]; + + int next = 0; + String subs = this.search.getText().toLowerCase(); + + for(FluidType type : Fluids.getInNiceOrder()) { + String name = I18nUtil.resolveKey(type.getUnlocalizedName()).toLowerCase(); + + if(name.contains(subs) && !type.hasNoID()) { + this.searchArray[next] = type; + next++; + + if(next >= 9) + return; + } + } + } +} diff --git a/src/main/java/com/hbm/items/IItemControlReceiver.java b/src/main/java/com/hbm/items/IItemControlReceiver.java new file mode 100644 index 000000000..f51bcec4a --- /dev/null +++ b/src/main/java/com/hbm/items/IItemControlReceiver.java @@ -0,0 +1,9 @@ +package com.hbm.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public interface IItemControlReceiver { + + public void receiveControl(ItemStack stack, NBTTagCompound data); +} diff --git a/src/main/java/com/hbm/items/ModItems.java b/src/main/java/com/hbm/items/ModItems.java index ad6f6d863..6f96de338 100644 --- a/src/main/java/com/hbm/items/ModItems.java +++ b/src/main/java/com/hbm/items/ModItems.java @@ -1228,6 +1228,7 @@ public class ModItems { public static Item chemistry_template; public static Item chemistry_icon; public static Item fluid_identifier; + public static Item fluid_identifier_multi; public static Item fluid_icon; public static Item siren_track; public static Item fluid_duct; @@ -2540,6 +2541,7 @@ public class ModItems { public static Item digamma_up_on_top; public static final int guiID_item_folder = 1099; + public static final int guiID_item_fluid = 1100; public static final int guiID_item_designator = 10100; public static final int guiID_item_sat_interface = 10101; public static final int guiID_item_box = 10102; @@ -4793,6 +4795,7 @@ public class ModItems { chemistry_template = new ItemChemistryTemplate().setUnlocalizedName("chemistry_template").setMaxStackSize(1).setCreativeTab(MainRegistry.templateTab).setTextureName(RefStrings.MODID + ":chemistry_template"); chemistry_icon = new ItemChemistryIcon().setUnlocalizedName("chemistry_icon").setMaxStackSize(1).setCreativeTab(null); fluid_identifier = new ItemFluidIdentifier().setUnlocalizedName("fluid_identifier").setMaxStackSize(1).setCreativeTab(MainRegistry.templateTab).setTextureName(RefStrings.MODID + ":fluid_identifier"); + fluid_identifier_multi = new ItemFluidIDMulti().setUnlocalizedName("fluid_identifier_multi").setMaxStackSize(1).setCreativeTab(MainRegistry.templateTab).setTextureName(RefStrings.MODID + ":fluid_identifier_multi"); fluid_icon = new ItemFluidIcon().setUnlocalizedName("fluid_icon").setCreativeTab(null).setTextureName(RefStrings.MODID + ":fluid_icon"); fluid_tank_empty = new Item().setUnlocalizedName("fluid_tank_empty").setCreativeTab(MainRegistry.controlTab).setTextureName(RefStrings.MODID + ":fluid_tank"); fluid_tank_full = new ItemFluidTank().setUnlocalizedName("fluid_tank_full").setContainerItem(ModItems.fluid_tank_empty).setCreativeTab(MainRegistry.controlTab).setTextureName(RefStrings.MODID + ":fluid_tank"); @@ -6592,6 +6595,7 @@ public class ModItems { //Machine Templates GameRegistry.registerItem(siren_track, siren_track.getUnlocalizedName()); GameRegistry.registerItem(fluid_identifier, fluid_identifier.getUnlocalizedName()); + GameRegistry.registerItem(fluid_identifier_multi, fluid_identifier_multi.getUnlocalizedName()); GameRegistry.registerItem(fluid_icon, fluid_icon.getUnlocalizedName()); GameRegistry.registerItem(fluid_duct, fluid_duct.getUnlocalizedName()); GameRegistry.registerItem(assembly_template, assembly_template.getUnlocalizedName()); diff --git a/src/main/java/com/hbm/items/machine/ItemFluidIDMulti.java b/src/main/java/com/hbm/items/machine/ItemFluidIDMulti.java new file mode 100644 index 000000000..02fa8c49c --- /dev/null +++ b/src/main/java/com/hbm/items/machine/ItemFluidIDMulti.java @@ -0,0 +1,142 @@ +package com.hbm.items.machine; + +import java.util.List; + +import com.hbm.inventory.fluid.FluidType; +import com.hbm.inventory.fluid.Fluids; +import com.hbm.items.IItemControlReceiver; +import com.hbm.items.ModItems; +import com.hbm.main.MainRegistry; +import com.hbm.util.I18nUtil; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +public class ItemFluidIDMulti extends Item implements IItemFluidIdentifier, IItemControlReceiver { + + IIcon overlayIcon; + + @Override + public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { + + if(!world.isRemote && !player.isSneaking()) { + FluidType primary = getType(stack, true); + FluidType secondary = getType(stack, false); + setType(stack, secondary, true); + setType(stack, primary, false); + world.playSoundAtEntity(player, "random.orb", 0.25F, 1.25F); + } + + if(world.isRemote && player.isSneaking()) { + player.openGui(MainRegistry.instance, ModItems.guiID_item_fluid, world, 0, 0, 0); + } + + return stack; + } + + @Override + public void receiveControl(ItemStack stack, NBTTagCompound data) { + if(data.hasKey("primary")) { + setType(stack, Fluids.fromID(data.getInteger("primary")), true); + } + if(data.hasKey("secondary")) { + setType(stack, Fluids.fromID(data.getInteger("secondary")), false); + } + } + + @Override + public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean bool) { + + if(!(stack.getItem() instanceof ItemFluidIdentifier)) + return; + + list.add(I18nUtil.resolveKey(getUnlocalizedName() + ".info")); + list.add(" " + I18n.format(getType(stack, true).getUnlocalizedName())); + list.add(I18nUtil.resolveKey(getUnlocalizedName() + ".info2")); + list.add(" " + I18n.format(getType(stack, false).getUnlocalizedName())); + } + + @Override + public ItemStack getContainerItem(ItemStack stack) { + return stack.copy(); + } + + @Override + public boolean hasContainerItem() { + return true; + } + + @Override + public boolean doesContainerItemLeaveCraftingGrid(ItemStack stack) { + return false; + } + + @Override + public FluidType getType(World world, int x, int y, int z, ItemStack stack) { + return getType(stack, true); + } + + @Override + public boolean doesSneakBypassUse(World world, int x, int y, int z, EntityPlayer player) { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister p_94581_1_) { + super.registerIcons(p_94581_1_); + + this.overlayIcon = p_94581_1_.registerIcon("hbm:fluid_identifier_overlay"); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIconFromDamageForRenderPass(int pass, int meta) { + return pass == 1 ? this.overlayIcon : super.getIconFromDamageForRenderPass(pass, meta); + } + + @Override + @SideOnly(Side.CLIENT) + public int getColorFromItemStack(ItemStack stack, int pass) { + if(pass == 0) { + return 16777215; + } else { + int j = getType(stack, true).getColor(); + + if(j < 0) { + j = 16777215; + } + + return j; + } + } + + public static void setType(ItemStack stack, FluidType type, boolean primary) { + if(!stack.hasTagCompound()) + stack.stackTagCompound = new NBTTagCompound(); + + stack.stackTagCompound.setInteger("fluid" + (primary ? 1 : 2), type.getID()); + } + + public static FluidType getType(ItemStack stack, boolean primary) { + if(!stack.hasTagCompound()) + return Fluids.NONE; + + int type = stack.stackTagCompound.getInteger("fluid" + (primary ? 1 : 2)); + return Fluids.fromID(type); + } +} diff --git a/src/main/java/com/hbm/packet/NBTItemControlPacket.java b/src/main/java/com/hbm/packet/NBTItemControlPacket.java new file mode 100644 index 000000000..7f03f6894 --- /dev/null +++ b/src/main/java/com/hbm/packet/NBTItemControlPacket.java @@ -0,0 +1,79 @@ +package com.hbm.packet; + +import java.io.IOException; + +import com.hbm.items.IItemControlReceiver; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +public class NBTItemControlPacket implements IMessage { + + PacketBuffer buffer; + + public NBTItemControlPacket() { } + + public NBTItemControlPacket(NBTTagCompound nbt) { + + this.buffer = new PacketBuffer(Unpooled.buffer()); + + try { + buffer.writeNBTTagCompoundToBuffer(nbt); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void fromBytes(ByteBuf buf) { + + if (buffer == null) { + buffer = new PacketBuffer(Unpooled.buffer()); + } + buffer.writeBytes(buf); + } + + @Override + public void toBytes(ByteBuf buf) { + + if (buffer == null) { + buffer = new PacketBuffer(Unpooled.buffer()); + } + buf.writeBytes(buffer); + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(NBTItemControlPacket m, MessageContext ctx) { + + EntityPlayer p = ctx.getServerHandler().playerEntity; + + try { + + NBTTagCompound nbt = m.buffer.readNBTTagCompoundFromBuffer(); + + if(nbt != null) { + ItemStack held = p.getHeldItem(); + + if(held != null && held.getItem() instanceof IItemControlReceiver) { + ((IItemControlReceiver) held.getItem()).receiveControl(held, nbt); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + } +} diff --git a/src/main/java/com/hbm/packet/PacketDispatcher.java b/src/main/java/com/hbm/packet/PacketDispatcher.java index f4abdc6e7..26b8fe391 100644 --- a/src/main/java/com/hbm/packet/PacketDispatcher.java +++ b/src/main/java/com/hbm/packet/PacketDispatcher.java @@ -99,6 +99,8 @@ public class PacketDispatcher { wrapper.registerMessage(ExplosionKnockbackPacket.Handler.class, ExplosionKnockbackPacket.class, i++, Side.CLIENT); //just go fuck yourself already wrapper.registerMessage(ExplosionVanillaNewTechnologyCompressedAffectedBlockPositionDataForClientEffectsAndParticleHandlingPacket.Handler.class, ExplosionVanillaNewTechnologyCompressedAffectedBlockPositionDataForClientEffectsAndParticleHandlingPacket.class, i++, Side.CLIENT); + //Packet to send NBT data from clients to the serverside held item + wrapper.registerMessage(NBTItemControlPacket.Handler.class, NBTItemControlPacket.class, i++, Side.SERVER); } } diff --git a/src/main/resources/assets/hbm/lang/de_DE.lang b/src/main/resources/assets/hbm/lang/de_DE.lang index fee5dabb7..507c32def 100644 --- a/src/main/resources/assets/hbm/lang/de_DE.lang +++ b/src/main/resources/assets/hbm/lang/de_DE.lang @@ -1352,6 +1352,9 @@ item.fluid_identifier.info=Universelle Flüssigkeits-Kennzeichnung für: item.fluid_identifier.usage0=Rechtsklicke Rohre, um ihnen die jeweilige Flüssigkeit zuzuweisen. item.fluid_identifier.usage1=Shift-rechtsklicke Rohre, um angeschlossene Rohre mit item.fluid_identifier.usage2=einer maximalen Reichweite von 64 Rohren zuzuweisen. +item.fluid_identifier_multi.name=Multi-Flüssigkeits-Kennzeichnung +item.fluid_identifier_multi.info=Universelle Flüssigkeits-Kennzeichnung für: +item.fluid_identifier_multi.info2=Sekundärer Typ: item.fluid_tank_empty.name=Leere universelle Flüssigkeitszelle item.fluid_tank_full.name=Universelle Flüssigkeitszelle: item.fluid_tank_lead_empty.name=Leere Gefahrenstoffzelle diff --git a/src/main/resources/assets/hbm/lang/en_US.lang b/src/main/resources/assets/hbm/lang/en_US.lang index baa894236..ffb765274 100644 --- a/src/main/resources/assets/hbm/lang/en_US.lang +++ b/src/main/resources/assets/hbm/lang/en_US.lang @@ -1584,6 +1584,9 @@ item.fluid_identifier.info=Universal fluid identifier for: item.fluid_identifier.usage0=Right click fluid ducts to designate them for that fluid. item.fluid_identifier.usage1=Shift right click fluid ducts to designate adjacent ducts item.fluid_identifier.usage2=up to a maximum range of 64 ducts. +item.fluid_identifier_multi.name=Multi Fluid Identifier +item.fluid_identifier_multi.info=Universal fluid identifier for: +item.fluid_identifier_multi.info2=Secondary type: item.fluid_tank_empty.name=Empty Universal Fluid Tank item.fluid_tank_full.name=Universal Fluid Tank: item.fluid_tank_lead_empty.name=Empty Hazardous Material Tank diff --git a/src/main/resources/assets/hbm/textures/gui/gui_planner.png b/src/main/resources/assets/hbm/textures/gui/gui_planner.png index 83c0e6f840360dce2e9d04ed3419649b328843ae..dabf8d89906a3e181e584c22a437cf3f172ecfd4 100644 GIT binary patch literal 1759 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/items/fluid_identifier_multi.png b/src/main/resources/assets/hbm/textures/items/fluid_identifier_multi.png new file mode 100644 index 0000000000000000000000000000000000000000..4ba81f10c97ae7ed3c6b828b2c10a2e478a962ab GIT binary patch literal 284 zcmV+%0ptFOP)`MBN_7;U08g&!NF z#nJSj&7o}I2}Gnw0*reA;ARQd?w()DtxN#5huGx!KF`wVuk5<6%ZmI0MMS@tnf%IL i!!TqGiv$b#|LX&AsZSh%*vAwA0000