From c8201ca317689109579afdb9bda80cba58246bc1 Mon Sep 17 00:00:00 2001 From: Azercoco <20425137+Azercoco@users.noreply.github.com> Date: Tue, 15 Aug 2023 00:36:53 +0200 Subject: [PATCH] Add Portable Storage Unit (#502) Closes #165. --- docs/ADDING_MATERIALS.md | 1 + .../modern_industrialization/lang/en_us.json | 3 + .../lang/untranslated/ko_kr.json | 3 + .../lang/untranslated/pt_br.json | 3 + .../lang/untranslated/ru_ru.json | 3 + .../lang/untranslated/zh_cn.json | 3 + .../lang/untranslated/zh_tw.json | 3 + .../models/item/portable_storage_unit.json | 6 + .../battery/portable_storage_unit.json | 29 ++ .../modern_industrialization/MIItem.java | 12 +- .../modern_industrialization/MIText.java | 2 + .../modern_industrialization/MITooltips.java | 264 ++++++++++++------ .../api/energy/EnergyApi.java | 61 +++- .../blocks/storage/barrel/BarrelItem.java | 4 - .../blocks/storage/tank/TankItem.java | 6 +- .../material/MaterialBuilderJSWrapper.java | 5 + .../kubejs/material/PartJsonCreator.java | 4 + .../definition/ItemDefinition.java | 4 +- .../items/ContainerItem.java | 6 +- .../items/ItemContainingItemHelper.java | 1 + .../items/PortableStorageUnit.java | 134 +++++++++ .../items/SteamDrillItem.java | 5 - .../items/armor/GraviChestPlateItem.java | 20 +- .../AbstractStorageMachineBlockEntity.java | 22 +- .../materials/MIMaterials.java | 10 +- .../materials/part/BatteryPart.java | 47 ++++ .../materials/part/MIParts.java | 2 +- .../util/TextHelper.java | 33 ++- .../textures/item/portable_storage_unit.png | Bin 0 -> 2257 bytes .../electric_age/portable_storage_unit.json | 18 ++ .../battery/portable_storage_unit_asbl.json | 27 ++ 31 files changed, 591 insertions(+), 150 deletions(-) create mode 100644 src/generated/resources/assets/modern_industrialization/models/item/portable_storage_unit.json create mode 100644 src/generated/resources/data/modern_industrialization/recipes/assembler_generated/electric_age/battery/portable_storage_unit.json create mode 100644 src/main/java/aztech/modern_industrialization/items/PortableStorageUnit.java create mode 100644 src/main/java/aztech/modern_industrialization/materials/part/BatteryPart.java create mode 100644 src/main/resources/assets/modern_industrialization/textures/item/portable_storage_unit.png create mode 100644 src/main/resources/data/modern_industrialization/patchouli_books/book/en_us/entries/electric_age/portable_storage_unit.json create mode 100644 src/main/resources/data/modern_industrialization/recipes/electric_age/battery/portable_storage_unit_asbl.json diff --git a/docs/ADDING_MATERIALS.md b/docs/ADDING_MATERIALS.md index 79dd06b4f..885ab04e7 100644 --- a/docs/ADDING_MATERIALS.md +++ b/docs/ADDING_MATERIALS.md @@ -32,6 +32,7 @@ MIMaterialEvents.addMaterials(event => { // and 8.0 blast resistance (also optional, default is 6.0) .machineCasing(8.0) // same as above but for machine casings but the custom name and path are optional .pipeCasing(8.0) // add a pipe casing, only blast resistance can be specified + .battery(5000000) // add a battery with 5M EU capacity for the Portable Storage Unit .ore({ "generate": true, // does the ore generate in the world "ore_set": "copper", // texture set, same principle as for blocks (found in "textures/materialsets/ores") diff --git a/src/generated/resources/assets/modern_industrialization/lang/en_us.json b/src/generated/resources/assets/modern_industrialization/lang/en_us.json index 3dbc35e59..a5ed50573 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/en_us.json +++ b/src/generated/resources/assets/modern_industrialization/lang/en_us.json @@ -852,6 +852,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "Plutonium Tiny Dust", "item.modern_industrialization.polyethylene_bucket": "Polyethylene Bucket", "item.modern_industrialization.polyvinyl_chloride_bucket": "Polyvinyl Chloride Bucket", + "item.modern_industrialization.portable_storage_unit": "Portable Storage Unit", "item.modern_industrialization.processing_unit": "Processing Unit", "item.modern_industrialization.processing_unit_board": "Processing Unit Board", "item.modern_industrialization.propene_bucket": "Propene Bucket", @@ -1464,6 +1465,7 @@ "text.modern_industrialization.BaseEuRecipe": "Recipe Base : %s", "text.modern_industrialization.BaseEuTotal": "Total : %s", "text.modern_industrialization.BaseEuTotalStored": "Total Energy Stored : %s", + "text.modern_industrialization.BatteryInStorageUnit": "Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "Blacklist mode enabled", "text.modern_industrialization.BookSubtitle": "Technology For Newbies", "text.modern_industrialization.Both": "Both", @@ -1525,6 +1527,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "⚠ Empty Filter", "text.modern_industrialization.Enabled": "Enabled", "text.modern_industrialization.EnergyFill": "Energy: %s %%", + "text.modern_industrialization.EnergyStored": "Energy Stored : %s", "text.modern_industrialization.Eu": "%s%s EU", "text.modern_industrialization.EuCable": "%s - Max network transfer : %s", "text.modern_industrialization.EuGenerationMode": "EU Generation", diff --git a/src/generated/resources/assets/modern_industrialization/lang/untranslated/ko_kr.json b/src/generated/resources/assets/modern_industrialization/lang/untranslated/ko_kr.json index d164c51ce..22a64ac90 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/untranslated/ko_kr.json +++ b/src/generated/resources/assets/modern_industrialization/lang/untranslated/ko_kr.json @@ -1030,6 +1030,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "작은 플루토늄 가루", "item.modern_industrialization.polyethylene_bucket": "[UNTRANSLATED] Polyethylene Bucket", "item.modern_industrialization.polyvinyl_chloride_bucket": "[UNTRANSLATED] Polyvinyl Chloride Bucket", + "item.modern_industrialization.portable_storage_unit": "[UNTRANSLATED] Portable Storage Unit", "item.modern_industrialization.processing_unit": "처리 유닛", "item.modern_industrialization.processing_unit_board": "처리 유닛 판", "item.modern_industrialization.propene_bucket": "[UNTRANSLATED] Propene Bucket", @@ -1674,6 +1675,7 @@ "text.modern_industrialization.BaseEuRecipe": "[UNTRANSLATED] Recipe Base : %s", "text.modern_industrialization.BaseEuTotal": "[UNTRANSLATED] Total : %s", "text.modern_industrialization.BaseEuTotalStored": "[UNTRANSLATED] Total Energy Stored : %s", + "text.modern_industrialization.BatteryInStorageUnit": "[UNTRANSLATED] Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "[UNTRANSLATED] Blacklist mode enabled", "text.modern_industrialization.BookSubtitle": "[UNTRANSLATED] Technology For Newbies", "text.modern_industrialization.Both": "[UNTRANSLATED] Both", @@ -1735,6 +1737,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "[UNTRANSLATED] ⚠ Empty Filter", "text.modern_industrialization.Enabled": "[UNTRANSLATED] Enabled", "text.modern_industrialization.EnergyFill": "[UNTRANSLATED] Energy: %s %%", + "text.modern_industrialization.EnergyStored": "[UNTRANSLATED] Energy Stored : %s", "text.modern_industrialization.Eu": "[UNTRANSLATED] %s%s EU", "text.modern_industrialization.EuCable": "[UNTRANSLATED] %s - Max network transfer : %s", "text.modern_industrialization.EuGenerationMode": "[UNTRANSLATED] EU Generation", diff --git a/src/generated/resources/assets/modern_industrialization/lang/untranslated/pt_br.json b/src/generated/resources/assets/modern_industrialization/lang/untranslated/pt_br.json index a1500914e..0c8411c2f 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/untranslated/pt_br.json +++ b/src/generated/resources/assets/modern_industrialization/lang/untranslated/pt_br.json @@ -852,6 +852,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "Pó Pequeno de Plutônio", "item.modern_industrialization.polyethylene_bucket": "Balde de Polietileno", "item.modern_industrialization.polyvinyl_chloride_bucket": "Balde de Policloreto de Vinila", + "item.modern_industrialization.portable_storage_unit": "[UNTRANSLATED] Portable Storage Unit", "item.modern_industrialization.processing_unit": "Unidade de Processamento", "item.modern_industrialization.processing_unit_board": "Placa de Unidade de Processamento", "item.modern_industrialization.propene_bucket": "Balde de Propileno", @@ -1466,6 +1467,7 @@ "text.modern_industrialization.BaseEuRecipe": "Receita Base : %s", "text.modern_industrialization.BaseEuTotal": "Total : %s", "text.modern_industrialization.BaseEuTotalStored": "Energia Armazenada Total : %s", + "text.modern_industrialization.BatteryInStorageUnit": "[UNTRANSLATED] Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "Modo Lista Negra ativado", "text.modern_industrialization.BookSubtitle": "Tecnologia para Novatos", "text.modern_industrialization.Both": "Ambos(as)", @@ -1527,6 +1529,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "⚠ Filtro Vazio", "text.modern_industrialization.Enabled": "Ativado", "text.modern_industrialization.EnergyFill": "Energia: %s %%", + "text.modern_industrialization.EnergyStored": "[UNTRANSLATED] Energy Stored : %s", "text.modern_industrialization.Eu": "%s%s EU", "text.modern_industrialization.EuCable": "%s - Transferência na Rede : %s", "text.modern_industrialization.EuGenerationMode": "Geração de EU", diff --git a/src/generated/resources/assets/modern_industrialization/lang/untranslated/ru_ru.json b/src/generated/resources/assets/modern_industrialization/lang/untranslated/ru_ru.json index cd8231370..5571da958 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/untranslated/ru_ru.json +++ b/src/generated/resources/assets/modern_industrialization/lang/untranslated/ru_ru.json @@ -852,6 +852,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "Плутониевый мельчайший порошок", "item.modern_industrialization.polyethylene_bucket": "Ведро полиэтилена", "item.modern_industrialization.polyvinyl_chloride_bucket": "Ведро поливинилхлорида", + "item.modern_industrialization.portable_storage_unit": "[UNTRANSLATED] Portable Storage Unit", "item.modern_industrialization.processing_unit": "Процессор", "item.modern_industrialization.processing_unit_board": "Плата для процессора", "item.modern_industrialization.propene_bucket": "Ведро пропилена", @@ -1466,6 +1467,7 @@ "text.modern_industrialization.BaseEuRecipe": "Основа рецепта: %s", "text.modern_industrialization.BaseEuTotal": "Всего: %s", "text.modern_industrialization.BaseEuTotalStored": "Хранит суммарной энергии: %s", + "text.modern_industrialization.BatteryInStorageUnit": "[UNTRANSLATED] Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "Включён режим чёрного списка", "text.modern_industrialization.BookSubtitle": "Технология для начинающих", "text.modern_industrialization.Both": "Оба", @@ -1527,6 +1529,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "⚠ Пустой фильтр", "text.modern_industrialization.Enabled": "Включён(а)", "text.modern_industrialization.EnergyFill": "Энергия: %s %%", + "text.modern_industrialization.EnergyStored": "[UNTRANSLATED] Energy Stored : %s", "text.modern_industrialization.Eu": "%s%s ЭЕ", "text.modern_industrialization.EuCable": "%s — Максимальная передача сети: %s", "text.modern_industrialization.EuGenerationMode": "Генерация ЭЕ", diff --git a/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_cn.json b/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_cn.json index 32335bf17..cafec8775 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_cn.json +++ b/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_cn.json @@ -852,6 +852,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "小堆钚粉", "item.modern_industrialization.polyethylene_bucket": "[UNTRANSLATED] Polyethylene Bucket", "item.modern_industrialization.polyvinyl_chloride_bucket": "[UNTRANSLATED] Polyvinyl Chloride Bucket", + "item.modern_industrialization.portable_storage_unit": "[UNTRANSLATED] Portable Storage Unit", "item.modern_industrialization.processing_unit": "处理单元", "item.modern_industrialization.processing_unit_board": "处理单元板", "item.modern_industrialization.propene_bucket": "[UNTRANSLATED] Propene Bucket", @@ -1464,6 +1465,7 @@ "text.modern_industrialization.BaseEuRecipe": "[UNTRANSLATED] Recipe Base : %s", "text.modern_industrialization.BaseEuTotal": "[UNTRANSLATED] Total : %s", "text.modern_industrialization.BaseEuTotalStored": "[UNTRANSLATED] Total Energy Stored : %s", + "text.modern_industrialization.BatteryInStorageUnit": "[UNTRANSLATED] Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "[UNTRANSLATED] Blacklist mode enabled", "text.modern_industrialization.BookSubtitle": "[UNTRANSLATED] Technology For Newbies", "text.modern_industrialization.Both": "[UNTRANSLATED] Both", @@ -1525,6 +1527,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "[UNTRANSLATED] ⚠ Empty Filter", "text.modern_industrialization.Enabled": "[UNTRANSLATED] Enabled", "text.modern_industrialization.EnergyFill": "[UNTRANSLATED] Energy: %s %%", + "text.modern_industrialization.EnergyStored": "[UNTRANSLATED] Energy Stored : %s", "text.modern_industrialization.Eu": "[UNTRANSLATED] %s%s EU", "text.modern_industrialization.EuCable": "[UNTRANSLATED] %s - Max network transfer : %s", "text.modern_industrialization.EuGenerationMode": "[UNTRANSLATED] EU Generation", diff --git a/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_tw.json b/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_tw.json index 807839d6e..85effdeec 100644 --- a/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_tw.json +++ b/src/generated/resources/assets/modern_industrialization/lang/untranslated/zh_tw.json @@ -1016,6 +1016,7 @@ "item.modern_industrialization.plutonium_tiny_dust": "[UNTRANSLATED] Plutonium Tiny Dust", "item.modern_industrialization.polyethylene_bucket": "[UNTRANSLATED] Polyethylene Bucket", "item.modern_industrialization.polyvinyl_chloride_bucket": "[UNTRANSLATED] Polyvinyl Chloride Bucket", + "item.modern_industrialization.portable_storage_unit": "[UNTRANSLATED] Portable Storage Unit", "item.modern_industrialization.processing_unit": "[UNTRANSLATED] Processing Unit", "item.modern_industrialization.processing_unit_board": "[UNTRANSLATED] Processing Unit Board", "item.modern_industrialization.propene_bucket": "[UNTRANSLATED] Propene Bucket", @@ -1671,6 +1672,7 @@ "text.modern_industrialization.BaseEuRecipe": "[UNTRANSLATED] Recipe Base : %s", "text.modern_industrialization.BaseEuTotal": "[UNTRANSLATED] Total : %s", "text.modern_industrialization.BaseEuTotalStored": "[UNTRANSLATED] Total Energy Stored : %s", + "text.modern_industrialization.BatteryInStorageUnit": "[UNTRANSLATED] Insert in a Portable Storage Unit to add %s of capacity", "text.modern_industrialization.Blacklist": "[UNTRANSLATED] Blacklist mode enabled", "text.modern_industrialization.BookSubtitle": "[UNTRANSLATED] Technology For Newbies", "text.modern_industrialization.Both": "[UNTRANSLATED] Both", @@ -1732,6 +1734,7 @@ "text.modern_industrialization.EmptyWhitelistWarning": "[UNTRANSLATED] ⚠ Empty Filter", "text.modern_industrialization.Enabled": "[UNTRANSLATED] Enabled", "text.modern_industrialization.EnergyFill": "[UNTRANSLATED] Energy: %s %%", + "text.modern_industrialization.EnergyStored": "[UNTRANSLATED] Energy Stored : %s", "text.modern_industrialization.Eu": "[UNTRANSLATED] %s%s EU", "text.modern_industrialization.EuCable": "[UNTRANSLATED] %s - Max network transfer : %s", "text.modern_industrialization.EuGenerationMode": "[UNTRANSLATED] EU Generation", diff --git a/src/generated/resources/assets/modern_industrialization/models/item/portable_storage_unit.json b/src/generated/resources/assets/modern_industrialization/models/item/portable_storage_unit.json new file mode 100644 index 000000000..3254cc6c7 --- /dev/null +++ b/src/generated/resources/assets/modern_industrialization/models/item/portable_storage_unit.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "modern_industrialization:item/portable_storage_unit" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/modern_industrialization/recipes/assembler_generated/electric_age/battery/portable_storage_unit.json b/src/generated/resources/data/modern_industrialization/recipes/assembler_generated/electric_age/battery/portable_storage_unit.json new file mode 100644 index 000000000..ea1f1db0b --- /dev/null +++ b/src/generated/resources/data/modern_industrialization/recipes/assembler_generated/electric_age/battery/portable_storage_unit.json @@ -0,0 +1,29 @@ +{ + "type": "modern_industrialization:assembler", + "duration": 200, + "eu": 8, + "item_inputs": [ + { + "amount": 4, + "tag": "c:battery_alloy_plates" + }, + { + "amount": 2, + "item": "modern_industrialization:battery_alloy_curved_plate" + }, + { + "amount": 2, + "item": "modern_industrialization:tin_cable" + }, + { + "amount": 1, + "item": "modern_industrialization:analog_circuit" + } + ], + "item_outputs": [ + { + "amount": 1, + "item": "modern_industrialization:portable_storage_unit" + } + ] +} \ No newline at end of file diff --git a/src/main/java/aztech/modern_industrialization/MIItem.java b/src/main/java/aztech/modern_industrialization/MIItem.java index a93df8524..d92a5c166 100644 --- a/src/main/java/aztech/modern_industrialization/MIItem.java +++ b/src/main/java/aztech/modern_industrialization/MIItem.java @@ -25,13 +25,9 @@ import static aztech.modern_industrialization.items.SortOrder.*; +import aztech.modern_industrialization.api.energy.EnergyApi; import aztech.modern_industrialization.definition.ItemDefinition; -import aztech.modern_industrialization.items.ConfigCardItem; -import aztech.modern_industrialization.items.FluidFuelItemHelper; -import aztech.modern_industrialization.items.ForgeTool; -import aztech.modern_industrialization.items.GuideBookItem; -import aztech.modern_industrialization.items.SortOrder; -import aztech.modern_industrialization.items.SteamDrillItem; +import aztech.modern_industrialization.items.*; import aztech.modern_industrialization.items.armor.GraviChestPlateItem; import aztech.modern_industrialization.items.armor.JetpackItem; import aztech.modern_industrialization.items.armor.QuantumArmorItem; @@ -53,6 +49,7 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.*; +import team.reborn.energy.api.base.SimpleEnergyItem; @SuppressWarnings("unused") public final class MIItem { @@ -149,6 +146,9 @@ public final class MIItem { public static final ItemDefinition DIESEL_CHAINSAW = itemHandheld("Diesel Chainsaw", "diesel_chainsaw", p -> new DieselToolItem(p, 12)) .withItemRegistrationEvent((item) -> FluidStorage.ITEM.registerForItems((stack, ctx) -> new FluidFuelItemHelper.ItemStorage(DieselToolItem.CAPACITY, ctx), item)); + public static final ItemDefinition PORTABLE_STORAGE_UNIT = itemHandheld("Portable Storage Unit", "portable_storage_unit", PortableStorageUnit::new) + .withItemRegistrationEvent(item -> EnergyApi.ITEM.registerForItems((stack, ctx) -> SimpleEnergyItem.createStorage(ctx, item.getEnergyCapacity(stack), item.getEnergyMaxInput(stack), item.getEnergyMaxOutput(stack)), item)); + // Armor public static final ItemDefinition RUBBER_HELMET = item("Rubber Helmet", "rubber_helmet", s -> new ArmorItem(RubberArmorMaterial.INSTANCE, EquipmentSlot.HEAD, s.maxCount(1)), ITEMS_OTHER); public static final ItemDefinition RUBBER_BOOTS = item("Rubber Boots", "rubber_boots", s -> new ArmorItem(RubberArmorMaterial.INSTANCE, EquipmentSlot.FEET, s.maxCount(1)), ITEMS_OTHER); diff --git a/src/main/java/aztech/modern_industrialization/MIText.java b/src/main/java/aztech/modern_industrialization/MIText.java index 83db16aa0..1e0208b87 100644 --- a/src/main/java/aztech/modern_industrialization/MIText.java +++ b/src/main/java/aztech/modern_industrialization/MIText.java @@ -52,6 +52,7 @@ public enum MIText { BaseEuRecipe("Recipe Base : %s"), BaseEuTotal("Total : %s"), BaseEuTotalStored("Total Energy Stored : %s"), + BatteryInStorageUnit("Insert in a Portable Storage Unit to add %s of capacity"), Blacklist("Blacklist mode enabled"), BookSubtitle("Technology For Newbies"), Both("Both"), @@ -113,6 +114,7 @@ public enum MIText { EmptyWhitelistWarning("⚠ Empty Filter"), Enabled("Enabled"), EnergyFill("Energy: %s %%"), + EnergyStored("Energy Stored : %s"), Eu("%s%s EU"), EuCable("%s - Max network transfer : %s"), EuGenerationMode("EU Generation"), diff --git a/src/main/java/aztech/modern_industrialization/MITooltips.java b/src/main/java/aztech/modern_industrialization/MITooltips.java index 70f60b8b1..4b75312fc 100644 --- a/src/main/java/aztech/modern_industrialization/MITooltips.java +++ b/src/main/java/aztech/modern_industrialization/MITooltips.java @@ -23,9 +23,11 @@ */ package aztech.modern_industrialization; +import aztech.modern_industrialization.api.energy.EnergyApi; import aztech.modern_industrialization.api.pipes.item.SpeedUpgrade; import aztech.modern_industrialization.blocks.OreBlock; import aztech.modern_industrialization.definition.FluidLike; +import aztech.modern_industrialization.items.PortableStorageUnit; import aztech.modern_industrialization.machines.MachineBlock; import aztech.modern_industrialization.machines.blockentities.multiblocks.ElectricBlastFurnaceBlockEntity; import aztech.modern_industrialization.machines.components.LubricantHelper; @@ -38,16 +40,22 @@ import aztech.modern_industrialization.util.TextHelper; import com.google.common.base.Preconditions; import java.util.*; -import java.util.function.Function; +import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; -import java.util.stream.Stream; +import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes; import net.minecraft.core.Registry; -import net.minecraft.network.chat.*; -import net.minecraft.world.item.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; @@ -91,14 +99,16 @@ public static void attachTooltip(ItemStack stack, List lines) { if (item != null) { boolean hasPrintRequiredShift = false; for (var tooltip : TOOLTIPS) { - if (tooltip.addTooltip.test(item)) { - if (!tooltip.requiresShift || CommonProxy.INSTANCE.hasShiftDown()) { - lines.addAll(tooltip.tooltipLines.apply(stack)); - } else if (tooltip.requiresShift && !hasPrintRequiredShift) { + Optional> maybeComponents = tooltip.tooltipLines.apply(stack, stack.getItem()); + if (!tooltip.requiresShift || CommonProxy.INSTANCE.hasShiftDown()) { + maybeComponents.ifPresent(lines::addAll); + } else if (tooltip.requiresShift && !hasPrintRequiredShift) { + if (maybeComponents.isPresent()) { lines.add(MIText.TooltipsShiftRequired.text().setStyle(DEFAULT_STYLE)); hasPrintRequiredShift = true; } } + } } } @@ -148,6 +158,17 @@ public Component parse(Number number) { } }; + public record NumberWithMax(Number number, Number max) { + } + + public static final Parser EU_MAXED_PARSER = new Parser<>() { + @Override + public Component parse(NumberWithMax numberWithMax) { + MutableComponent component = TextHelper.getEuTextMaxed(numberWithMax.number, numberWithMax.max); + return component.withStyle(NUMBER_TEXT); + } + }; + public static final Parser FLUID_PARSER = new Parser<>() { @Override public Component parse(Fluid fluid) { @@ -181,84 +202,149 @@ public Component parse(Double ratio) { // Tooltips - public static final TooltipAttachment CABLES = TooltipAttachment - .of((item) -> item instanceof PipeItem pipe && MIPipes.ELECTRICITY_PIPE_TIER.containsKey(pipe), itemStack -> { - var tier = MIPipes.ELECTRICITY_PIPE_TIER.get((PipeItem) itemStack.getItem()); - return new Line(MIText.EuCable).arg(tier.englishName).arg(tier.getMaxTransfer(), EU_PER_TICK_PARSER).build(); + public static final TooltipAttachment BATTERIES = TooltipAttachment.of( + (itemStack, item) -> { + if (PortableStorageUnit.CAPACITY_PER_BATTERY.containsKey(item)) { + var capacity = PortableStorageUnit.CAPACITY_PER_BATTERY.get(itemStack.getItem()); + return Optional.of(new Line(MIText.BatteryInStorageUnit).arg(capacity, EU_PARSER).build()); + } else { + return Optional.empty(); + } + }); + + public static final TooltipAttachment CABLES = TooltipAttachment.of( + (itemStack, item) -> { + if (item instanceof PipeItem pipe && MIPipes.ELECTRICITY_PIPE_TIER.containsKey(pipe)) { + var tier = MIPipes.ELECTRICITY_PIPE_TIER.get((PipeItem) itemStack.getItem()); + return Optional.of(new Line(MIText.EuCable).arg(tier.englishName).arg(tier.getMaxTransfer(), EU_PER_TICK_PARSER).build()); + } else { + return Optional.empty(); + } }); public static final TooltipAttachment COILS = TooltipAttachment.of( - (item) -> item instanceof BlockItem blockItem - && ElectricBlastFurnaceBlockEntity.tiersByCoil.containsKey(Registry.BLOCK.getKey(blockItem.getBlock())), - (itemStack) -> { - long eu = ElectricBlastFurnaceBlockEntity.tiersByCoil.get(Registry.BLOCK.getKey(((BlockItem) itemStack.getItem()).getBlock())) - .maxBaseEu(); - return new Line(MIText.EbfMaxEu).arg(eu).build(); + (itemStack, item) -> { + if (item instanceof BlockItem blockItem + && ElectricBlastFurnaceBlockEntity.tiersByCoil.containsKey(Registry.BLOCK.getKey(blockItem.getBlock()))) { + long eu = ElectricBlastFurnaceBlockEntity.tiersByCoil.get(Registry.BLOCK.getKey(((BlockItem) itemStack.getItem()).getBlock())) + .maxBaseEu(); + return Optional.of(new Line(MIText.EbfMaxEu).arg(eu).build()); + } else { + return Optional.empty(); + } }); - public static final TooltipAttachment CREATIVE_FLIGHT = TooltipAttachment - .of((item) -> item == MIItem.QUANTUM_CHESTPLATE.asItem() || item == MIItem.GRAVICHESTPLATE.asItem(), - (itemStack) -> new Line(MIText.AllowCreativeFlight).build()) - .noShiftRequired(); + public static final TooltipAttachment CREATIVE_FLIGHT = TooltipAttachment.of( + (itemStack, item) -> { + if (item == MIItem.QUANTUM_CHESTPLATE.asItem() || item == MIItem.GRAVICHESTPLATE.asItem()) { + return Optional.of(new Line(MIText.AllowCreativeFlight).build()); + } else { + return Optional.empty(); + } + }).noShiftRequired(); + + public static final TooltipAttachment ENERGY_STORED_ITEM = TooltipAttachment.of( + (itemStack, item) -> { + if (Registry.ITEM.getKey(item).getNamespace().equals(ModernIndustrialization.MOD_ID)) { + var energyStorage = ContainerItemContext.withConstant(itemStack).find(EnergyApi.ITEM); + if (energyStorage != null) { + long capacity = energyStorage.getCapacity(); + if (capacity > 0) { + return Optional.of(new Line(MIText.EnergyStored) + .arg(new NumberWithMax(energyStorage.getAmount(), capacity), EU_MAXED_PARSER).build()); + } + } + } + return Optional.empty(); + }).noShiftRequired(); public static final TooltipAttachment LUBRICANT_BUCKET = TooltipAttachment.of(MIFluids.LUBRICANT.getBucket(), new Line(MIText.LubricantTooltip).arg(LubricantHelper.mbPerTick)); public static final TooltipAttachment GUNPOWDER = TooltipAttachment.of(Items.GUNPOWDER, MIText.GunpowderUpgrade); - public static final TooltipAttachment MACHINE_TOOLTIPS = TooltipAttachment.ofMultiline( - (item) -> item instanceof BlockItem blockItem && blockItem.getBlock() instanceof MachineBlock machineBlock - && !machineBlock.getBlockEntityInstance().getTooltips().isEmpty(), - (itemStack) -> (((MachineBlock) ((BlockItem) itemStack.getItem()).getBlock()).getBlockEntityInstance()).getTooltips()); - - public static final TooltipAttachment NUCLEAR = TooltipAttachment.ofMultiline(item -> item.asItem() instanceof NuclearAbsorbable, (itemStack) -> { - List tooltips = new LinkedList<>(); - long remAbs = ((NuclearAbsorbable) itemStack.getItem()).getRemainingDesintegrations(itemStack); - tooltips.add(new MITooltips.Line(MIText.RemAbsorption).arg(remAbs).arg(((NuclearAbsorbable) itemStack.getItem()).desintegrationMax).build()); - if (itemStack.getItem() instanceof NuclearFuel fuel) { - long totalEu = (long) fuel.totalEUbyDesintegration * fuel.desintegrationMax; - tooltips.add(new MITooltips.Line(MIText.BaseEuTotalStored).arg(totalEu, MITooltips.EU_PARSER).build()); - } - return tooltips; - }); - - public static final TooltipAttachment ORES = TooltipAttachment - .ofMultiline((item) -> item instanceof BlockItem blockItem && blockItem.getBlock() instanceof OreBlock, (itemStack) -> { - OreBlock oreBlock = (OreBlock) ((BlockItem) itemStack.getItem()).getBlock(); - List lines = new LinkedList<>(); - MIConfig config = MIConfig.getConfig(); - - if (config.generateOres && !config.blacklistedOres.contains(oreBlock.materialName) && oreBlock.params.generate) { - lines.add(new Line(MIText.OreGenerationTooltipY).arg(-64).arg(oreBlock.params.maxYLevel).build()); - lines.add(new Line(MIText.OreGenerationTooltipVeinFrequency).arg(oreBlock.params.veinsPerChunk).build()); - lines.add(new Line(MIText.OreGenerationTooltipVeinSize).arg(oreBlock.params.veinSize).build()); + public static final TooltipAttachment MACHINE_TOOLTIPS = TooltipAttachment.ofMultilines( + (itemStack, item) -> { + if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof MachineBlock machineBlock + && !machineBlock.getBlockEntityInstance().getTooltips().isEmpty()) { + return Optional.of((((MachineBlock) ((BlockItem) itemStack.getItem()).getBlock()).getBlockEntityInstance()).getTooltips()); + } else { - lines.add(new Line(MIText.OreNotGenerated).build()); + return Optional.empty(); } - return lines; }); - public static final TooltipAttachment SPEED_UPGRADES = TooltipAttachment.of(SpeedUpgrade.UPGRADES::containsKey, - (itemStack) -> new Line(MIText.TooltipSpeedUpgrade).arg(SpeedUpgrade.UPGRADES.get(itemStack.getItem())).build()); + public static final TooltipAttachment NUCLEAR = TooltipAttachment.ofMultilines( + (itemStack, item) -> { + if (item instanceof NuclearAbsorbable) { + List tooltips = new LinkedList<>(); + long remAbs = ((NuclearAbsorbable) itemStack.getItem()).getRemainingDesintegrations(itemStack); + tooltips.add(new MITooltips.Line(MIText.RemAbsorption).arg(remAbs) + .arg(((NuclearAbsorbable) itemStack.getItem()).desintegrationMax).build()); + if (itemStack.getItem() instanceof NuclearFuel fuel) { + long totalEu = (long) fuel.totalEUbyDesintegration * fuel.desintegrationMax; + tooltips.add(new MITooltips.Line(MIText.BaseEuTotalStored).arg(totalEu, MITooltips.EU_PARSER).build()); + } + return Optional.of(tooltips); + } else { + return Optional.empty(); + } + }); - public static final TooltipAttachment UPGRADES = TooltipAttachment.ofMultiline(item -> UpgradeComponent.getExtraEu(item) > 0, (itemStack) -> { - List lines = new LinkedList<>(); - lines.add(new Line(MIText.MachineUpgrade).arg(UpgradeComponent.getExtraEu(itemStack.getItem()), EU_PER_TICK_PARSER).build()); + public static final TooltipAttachment ORES = TooltipAttachment.ofMultilines( + (itemStack, item) -> { + if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof OreBlock) { + OreBlock oreBlock = (OreBlock) ((BlockItem) itemStack.getItem()).getBlock(); + List lines = new LinkedList<>(); + MIConfig config = MIConfig.getConfig(); + + if (config.generateOres && !config.blacklistedOres.contains(oreBlock.materialName) && oreBlock.params.generate) { + lines.add(new Line(MIText.OreGenerationTooltipY).arg(-64).arg(oreBlock.params.maxYLevel).build()); + lines.add(new Line(MIText.OreGenerationTooltipVeinFrequency).arg(oreBlock.params.veinsPerChunk).build()); + lines.add(new Line(MIText.OreGenerationTooltipVeinSize).arg(oreBlock.params.veinSize).build()); + } else { + lines.add(new Line(MIText.OreNotGenerated).build()); + } + return Optional.of(lines); + } else { + return Optional.empty(); + } + }); - if (itemStack.getCount() > 1) { - lines.add(new Line(MIText.MachineUpgradeStack) - .arg(itemStack.getCount() * UpgradeComponent.getExtraEu(itemStack.getItem()), EU_PER_TICK_PARSER).build()); - } - return lines; - }); + public static final TooltipAttachment SPEED_UPGRADES = TooltipAttachment.of( + (itemStack, item) -> { + if (SpeedUpgrade.UPGRADES.containsKey(item)) { + return Optional.of(new Line(MIText.TooltipSpeedUpgrade).arg(SpeedUpgrade.UPGRADES.get(item)).build()); + } else { + return Optional.empty(); + } + + }); + + public static final TooltipAttachment UPGRADES = TooltipAttachment.ofMultilines( + (itemStack, item) -> { + if (UpgradeComponent.getExtraEu(item) > 0) { + + List lines = new LinkedList<>(); + lines.add(new Line(MIText.MachineUpgrade).arg(UpgradeComponent.getExtraEu(itemStack.getItem()), EU_PER_TICK_PARSER).build()); + + if (itemStack.getCount() > 1) { + lines.add(new Line(MIText.MachineUpgradeStack) + .arg(itemStack.getCount() * UpgradeComponent.getExtraEu(itemStack.getItem()), EU_PER_TICK_PARSER).build()); + } + return Optional.of(lines); + } else { + return Optional.empty(); + } + }); - public static final TooltipAttachment STEAM_DRILL = TooltipAttachment.ofMultiline(MIItem.STEAM_MINING_DRILL, + public static final TooltipAttachment STEAM_DRILL = TooltipAttachment.ofMultilines(MIItem.STEAM_MINING_DRILL, MIText.SteamDrillWaterHelp, MIText.SteamDrillFuelHelp, MIText.SteamDrillProfit, MIText.SteamDrillToggle); - public static final TooltipAttachment CONFIG_CARD_HELP = TooltipAttachment.ofMultiline(MIItem.CONFIG_CARD, + public static final TooltipAttachment CONFIG_CARD_HELP = TooltipAttachment.ofMultilines(MIItem.CONFIG_CARD, MIText.ConfigCardHelpCamouflage1, MIText.ConfigCardHelpCamouflage2, MIText.ConfigCardHelpCamouflage3, @@ -290,8 +376,13 @@ private static void add(Predicate attachTo, String translationId, Stri TOOLTIPS_ENGLISH_TRANSLATION.put(translationKey[i], englishTooltipsLine[i]); } - MITooltips.TooltipAttachment.ofMultiline(attachTo::test, itemStack -> Arrays.stream(translationKey) - .map(s -> Component.translatable(s).withStyle(MITooltips.DEFAULT_STYLE)).collect(Collectors.toList())); + MITooltips.TooltipAttachment.ofMultilines((itemStack, item) -> { + if (attachTo.test(item)) { + return Optional.of(Arrays.stream(translationKey).map(Component::translatable).collect(Collectors.toList())); + } else { + return Optional.empty(); + } + }); } private static void add(ItemLike itemLike, String... englishTooltipsLine) { @@ -322,43 +413,44 @@ private static void add(String itemId, String... englishTooltipsLine) { public static class TooltipAttachment implements Comparable { - public final Predicate addTooltip; - public final Function> tooltipLines; + public final BiFunction>> tooltipLines; public boolean requiresShift = true; public int priority = 0; - public static TooltipAttachment ofMultiline(Predicate addTooltip, Function> tooltipLines) { - return new TooltipAttachment(addTooltip, tooltipLines); + public static TooltipAttachment of(ItemLike itemLike, MIText text) { + return of(itemLike, new Line(text)); } - public static TooltipAttachment ofMultiline(ItemLike itemLike, Function> tooltips) { - return new TooltipAttachment((item) -> item == itemLike.asItem(), tooltips); - } + public static TooltipAttachment of(ItemLike itemLike, Line line) { - public static TooltipAttachment ofMultiline(ItemLike itemLike, MIText... tooltipLines) { - Preconditions.checkArgument(tooltipLines.length > 0); - var tooltip = Stream.of(tooltipLines).map(t -> new Line(t).build()).toList(); - return new TooltipAttachment(item -> item == itemLike.asItem(), stack -> tooltip); + return new TooltipAttachment( + (itemStack, item) -> itemStack.getItem() == itemLike.asItem() ? Optional.of(List.of(line.build())) : Optional.empty()); } - public static TooltipAttachment of(Predicate addTooltip, Function tooltips) { - return ofMultiline(addTooltip, (item -> List.of(tooltips.apply(item)))); + public static TooltipAttachment of(BiFunction> tooltipLines) { + + return new TooltipAttachment((itemStack, item) -> tooltipLines.apply(itemStack, item).map(List::of)); } - public static TooltipAttachment of(ItemLike itemLike, Function tooltips) { - return ofMultiline(itemLike, (item -> List.of(tooltips.apply(item)))); + public static TooltipAttachment ofMultilines(BiFunction>> tooltipLines) { + return new TooltipAttachment(tooltipLines); } - public static TooltipAttachment of(ItemLike itemLike, MIText text) { - return of(itemLike, new Line(text)); + public static TooltipAttachment ofMultilines(ItemLike itemLike, List tooltipLines) { + return new TooltipAttachment((itemStack, item) -> { + if (itemStack.getItem() == itemLike.asItem()) { + return Optional.of(tooltipLines); + } else { + return Optional.empty(); + } + }); } - public static TooltipAttachment of(ItemLike itemLike, Line line) { - return of(itemLike, (item) -> line.build()); + public static TooltipAttachment ofMultilines(ItemLike itemLike, MIText... tooltipLines) { + return ofMultilines(itemLike, Arrays.stream(tooltipLines).map(MIText::text).collect(Collectors.toList())); } - private TooltipAttachment(Predicate addTooltip, Function> tooltipLines) { - this.addTooltip = addTooltip; + private TooltipAttachment(BiFunction>> tooltipLines) { this.tooltipLines = tooltipLines; MITooltips.TOOLTIPS.add(this); } diff --git a/src/main/java/aztech/modern_industrialization/api/energy/EnergyApi.java b/src/main/java/aztech/modern_industrialization/api/energy/EnergyApi.java index d0addb1aa..cfdb02f7a 100644 --- a/src/main/java/aztech/modern_industrialization/api/energy/EnergyApi.java +++ b/src/main/java/aztech/modern_industrialization/api/energy/EnergyApi.java @@ -24,16 +24,21 @@ package aztech.modern_industrialization.api.energy; import aztech.modern_industrialization.MIConfig; +import aztech.modern_industrialization.MIIdentifier; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; +import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup; +import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import team.reborn.energy.api.EnergyStorage; import team.reborn.energy.api.base.DelegatingEnergyStorage; +import team.reborn.energy.api.base.LimitingEnergyStorage; public class EnergyApi { public static final BlockApiLookup SIDED = BlockApiLookup - .get(new ResourceLocation("modern_industrialization:sided_mi_energy_storage"), MIEnergyStorage.class, Direction.class); + .get(new MIIdentifier("sided_mi_energy_storage"), MIEnergyStorage.class, Direction.class); + public static final ItemApiLookup ITEM = ItemApiLookup + .get(new MIIdentifier("energy_storage"), EnergyStorage.class, ContainerItemContext.class); private static final ThreadLocal IN_COMPAT = ThreadLocal.withInitial(() -> false); @@ -93,7 +98,6 @@ public long getCapacity() { IN_COMPAT.set(false); } }); - SIDED.registerFallback((world, pos, state, blockEntity, context) -> { if (IN_COMPAT.get()) { return null; @@ -107,11 +111,62 @@ public long getCapacity() { IN_COMPAT.set(false); } }); + + EnergyStorage.ITEM.registerFallback((stack, ctx) -> { + if (IN_COMPAT.get()) { + return null; + } + + IN_COMPAT.set(true); + try { + return ITEM.find(stack, ctx); + } finally { + IN_COMPAT.set(false); + } + }); + ITEM.registerFallback((stack, ctx) -> { + if (IN_COMPAT.get()) { + return null; + } + + IN_COMPAT.set(true); + try { + return EnergyStorage.ITEM.find(stack, ctx); + } finally { + IN_COMPAT.set(false); + } + }); } else { SIDED.registerFallback((world, pos, state, blockEntity, context) -> { EnergyStorage trStorage = EnergyStorage.SIDED.find(world, pos, state, blockEntity, context); return trStorage == null || !trStorage.supportsInsertion() ? null : new InsertOnlyTrStorage(trStorage); }); + ITEM.registerFallback((stack, ctx) -> { + if (IN_COMPAT.get()) { + return null; + } + + IN_COMPAT.set(true); + try { + EnergyStorage trStorage = EnergyStorage.ITEM.find(stack, ctx); + return trStorage == null || !trStorage.supportsInsertion() ? null : new LimitingEnergyStorage(trStorage, Long.MAX_VALUE, 0); + } finally { + IN_COMPAT.set(false); + } + }); + EnergyStorage.ITEM.registerFallback((stack, ctx) -> { + if (IN_COMPAT.get()) { + return null; + } + + IN_COMPAT.set(true); + try { + EnergyStorage miStorage = ITEM.find(stack, ctx); + return miStorage == null || !miStorage.supportsExtraction() ? null : new LimitingEnergyStorage(miStorage, 0, Long.MAX_VALUE); + } finally { + IN_COMPAT.set(false); + } + }); } } diff --git a/src/main/java/aztech/modern_industrialization/blocks/storage/barrel/BarrelItem.java b/src/main/java/aztech/modern_industrialization/blocks/storage/barrel/BarrelItem.java index 9e2d1ee6f..47eb93671 100644 --- a/src/main/java/aztech/modern_industrialization/blocks/storage/barrel/BarrelItem.java +++ b/src/main/java/aztech/modern_industrialization/blocks/storage/barrel/BarrelItem.java @@ -104,8 +104,4 @@ public boolean overrideOtherStackedOnMe(ItemStack stack, ItemStack otherStack, S return handleOtherStackedOnMe(stack, otherStack, slot, clickType, player, cursorStackReference); } - @Override - public ItemVariant getBlankResource() { - return ItemVariant.blank(); - } } diff --git a/src/main/java/aztech/modern_industrialization/blocks/storage/tank/TankItem.java b/src/main/java/aztech/modern_industrialization/blocks/storage/tank/TankItem.java index a2d83b812..0ebfd791f 100644 --- a/src/main/java/aztech/modern_industrialization/blocks/storage/tank/TankItem.java +++ b/src/main/java/aztech/modern_industrialization/blocks/storage/tank/TankItem.java @@ -48,11 +48,6 @@ public void registerItemApi() { (stack, context) -> new GenericItemStorage<>(this, context), this); } - @Override - public FluidVariant getBlankResource() { - return FluidVariant.blank(); - } - @Override public FluidVariant getResource(ItemStack stack) { CompoundTag tag = stack.getTagElement("BlockEntityTag"); @@ -67,6 +62,7 @@ public FluidVariant getResource(ItemStack stack) { public void setResourceNoClean(ItemStack stack, FluidVariant resource) { CompoundTag tag = stack.getOrCreateTagElement("BlockEntityTag"); NbtHelper.putFluid(tag, "fluid", resource); + onChange(stack); } @Override diff --git a/src/main/java/aztech/modern_industrialization/compat/kubejs/material/MaterialBuilderJSWrapper.java b/src/main/java/aztech/modern_industrialization/compat/kubejs/material/MaterialBuilderJSWrapper.java index d4b5f6d6c..3f0454560 100644 --- a/src/main/java/aztech/modern_industrialization/compat/kubejs/material/MaterialBuilderJSWrapper.java +++ b/src/main/java/aztech/modern_industrialization/compat/kubejs/material/MaterialBuilderJSWrapper.java @@ -74,6 +74,11 @@ public MaterialBuilderJSWrapper addExternalPart(String part, String id) { return addExternalPart(part, id, id); } + public MaterialBuilderJSWrapper battery(long energyCapacity) { + materialBuilder.addParts(creator.batteryPart(energyCapacity)); + return this; + } + public MaterialBuilderJSWrapper barrel(int stackCapacity) { materialBuilder.addParts(creator.barrelPart(stackCapacity)); return this; diff --git a/src/main/java/aztech/modern_industrialization/compat/kubejs/material/PartJsonCreator.java b/src/main/java/aztech/modern_industrialization/compat/kubejs/material/PartJsonCreator.java index ec4ecdbab..bcc29b732 100644 --- a/src/main/java/aztech/modern_industrialization/compat/kubejs/material/PartJsonCreator.java +++ b/src/main/java/aztech/modern_industrialization/compat/kubejs/material/PartJsonCreator.java @@ -45,6 +45,10 @@ public PartTemplate customRegularPart(String englishName, String name) { return new PartTemplate(englishName, name); } + public PartTemplate batteryPart(long energyCapacity) { + return MIParts.BATTERY.of(energyCapacity); + } + public PartTemplate barrelPart(int stackCapacity) { return MIParts.BARREL.of(stackCapacity); } diff --git a/src/main/java/aztech/modern_industrialization/definition/ItemDefinition.java b/src/main/java/aztech/modern_industrialization/definition/ItemDefinition.java index a26ea3d3c..ffe4d2286 100644 --- a/src/main/java/aztech/modern_industrialization/definition/ItemDefinition.java +++ b/src/main/java/aztech/modern_industrialization/definition/ItemDefinition.java @@ -37,7 +37,7 @@ public class ItemDefinition extends Definition implements ItemLi public final SortOrder sortOrder; public final BiConsumer modelGenerator; - private Consumer onItemRegistrationEvent; + private Consumer onItemRegistrationEvent; public ItemDefinition(String englishName, String id, T item, BiConsumer modelGenerator, SortOrder sortOrder) { @@ -48,7 +48,7 @@ public ItemDefinition(String englishName, String id, T item, this.sortOrder = sortOrder; } - public ItemDefinition withItemRegistrationEvent(Consumer onItemRegistrationEvent) { + public ItemDefinition withItemRegistrationEvent(Consumer onItemRegistrationEvent) { this.onItemRegistrationEvent = onItemRegistrationEvent; return this; } diff --git a/src/main/java/aztech/modern_industrialization/items/ContainerItem.java b/src/main/java/aztech/modern_industrialization/items/ContainerItem.java index a305f8d35..3463debeb 100644 --- a/src/main/java/aztech/modern_industrialization/items/ContainerItem.java +++ b/src/main/java/aztech/modern_industrialization/items/ContainerItem.java @@ -40,8 +40,6 @@ */ public interface ContainerItem> { - T getBlankResource(); - T getResource(ItemStack stack); void setResourceNoClean(ItemStack stack, T resource); @@ -92,6 +90,7 @@ default long getAmount(ItemStack stack) { default void setAmountNoClean(ItemStack stack, long amount) { if (!getBehaviour().isCreative()) { stack.getOrCreateTagElement("BlockEntityTag").putLong("amt", amount); + onChange(stack); } } @@ -113,6 +112,9 @@ default boolean isEmpty(ItemStack stack) { return getAmount(stack) == 0; } + default void onChange(ItemStack stack) { + } + StorageBehaviour getBehaviour(); class GenericItemStorage> implements SingleSlotStorage { diff --git a/src/main/java/aztech/modern_industrialization/items/ItemContainingItemHelper.java b/src/main/java/aztech/modern_industrialization/items/ItemContainingItemHelper.java index 2a1e3239f..7ac36a225 100644 --- a/src/main/java/aztech/modern_industrialization/items/ItemContainingItemHelper.java +++ b/src/main/java/aztech/modern_industrialization/items/ItemContainingItemHelper.java @@ -101,5 +101,6 @@ default ItemVariant getResource(ItemStack stack) { @Override default void setResourceNoClean(ItemStack stack, ItemVariant item) { stack.getOrCreateTagElement("BlockEntityTag").put("item", item.toNbt()); + onChange(stack); } } diff --git a/src/main/java/aztech/modern_industrialization/items/PortableStorageUnit.java b/src/main/java/aztech/modern_industrialization/items/PortableStorageUnit.java new file mode 100644 index 000000000..6605ad96a --- /dev/null +++ b/src/main/java/aztech/modern_industrialization/items/PortableStorageUnit.java @@ -0,0 +1,134 @@ +/* + * MIT License + * + * Copyright (c) 2020 Azercoco & Technici4n + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package aztech.modern_industrialization.items; + +import aztech.modern_industrialization.blocks.storage.StorageBehaviour; +import aztech.modern_industrialization.blocks.storage.barrel.BarrelTooltipData; +import it.unimi.dsi.fastutil.objects.Reference2LongMap; +import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; +import java.util.Optional; +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; +import net.minecraft.world.entity.SlotAccess; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import team.reborn.energy.api.base.SimpleEnergyItem; + +public class PortableStorageUnit extends Item implements ItemContainingItemHelper { + + public static final Reference2LongMap CAPACITY_PER_BATTERY = new Reference2LongOpenHashMap<>(); + private final static int MAX_BATTERY_COUNT = 10000; + + public PortableStorageUnit(Properties properties) { + super(properties.stacksTo(1)); + } + + @Override + public void onChange(ItemStack stack) { + this.setStoredEnergy(stack, Math.min(this.getEnergyCapacity(stack), this.getStoredEnergy(stack))); + } + + public long getEnergyCapacity(ItemStack stack) { + if (this.isEmpty(stack)) { + return 0; + } else { + return CAPACITY_PER_BATTERY.getLong(this.getResource(stack).getItem()) * this.getAmount(stack); + } + } + + public long getEnergyMaxInput(ItemStack stack) { + return Long.MAX_VALUE; + } + + public long getEnergyMaxOutput(ItemStack stack) { + return Long.MAX_VALUE; + } + + @Override + public StorageBehaviour getBehaviour() { + + return new StorageBehaviour<>() { + @Override + public long getCapacityForResource(ItemVariant resource) { + return MAX_BATTERY_COUNT; + } + + public boolean canInsert(ItemVariant maybeBattery) { + return CAPACITY_PER_BATTERY.containsKey(maybeBattery.getItem()); + } + }; + } + + @Override + public boolean overrideStackedOnOther(ItemStack stackBarrel, Slot slot, ClickAction clickType, Player player) { + return handleStackedOnOther(stackBarrel, slot, clickType, player); + } + + @Override + public boolean overrideOtherStackedOnMe(ItemStack stack, ItemStack otherStack, Slot slot, ClickAction clickType, Player player, + SlotAccess cursorStackReference) { + return handleOtherStackedOnMe(stack, otherStack, slot, clickType, player, cursorStackReference); + } + + public Optional getTooltipImage(ItemStack stack) { + if (!isEmpty(stack)) { + return Optional.of(new BarrelTooltipData(getResource(stack), getAmount(stack), + MAX_BATTERY_COUNT, false)); + } + + return Optional.empty(); + } + + @Override + public boolean isBarVisible(ItemStack stack) { + return getEnergyCapacity(stack) > 0; + } + + @Override + public int getBarWidth(ItemStack stack) { + if (getEnergyCapacity(stack) > 0) { + return (int) Math.round(getStoredEnergy(stack) / (double) getEnergyCapacity(stack) * 13); + } else { + return 0; + } + } + + /** + * @return The energy stored in the stack. Count is ignored. + */ + public long getStoredEnergy(ItemStack stack) { + return SimpleEnergyItem.getStoredEnergyUnchecked(stack); + } + + /** + * Directly set the energy stored in the stack. Count is ignored. + * It's up to callers to ensure that the new amount is >= 0 and <= capacity. + */ + public void setStoredEnergy(ItemStack stack, long newAmount) { + SimpleEnergyItem.setStoredEnergyUnchecked(stack, newAmount); + } +} diff --git a/src/main/java/aztech/modern_industrialization/items/SteamDrillItem.java b/src/main/java/aztech/modern_industrialization/items/SteamDrillItem.java index 9afea1f78..a3fb4b92b 100644 --- a/src/main/java/aztech/modern_industrialization/items/SteamDrillItem.java +++ b/src/main/java/aztech/modern_industrialization/items/SteamDrillItem.java @@ -374,11 +374,6 @@ public void appendHoverText(ItemStack stack, @Nullable Level world, List getBehaviour() { return DRILL_BEHAVIOUR; diff --git a/src/main/java/aztech/modern_industrialization/items/armor/GraviChestPlateItem.java b/src/main/java/aztech/modern_industrialization/items/armor/GraviChestPlateItem.java index 112518f07..1ab1bd082 100644 --- a/src/main/java/aztech/modern_industrialization/items/armor/GraviChestPlateItem.java +++ b/src/main/java/aztech/modern_industrialization/items/armor/GraviChestPlateItem.java @@ -23,10 +23,7 @@ */ package aztech.modern_industrialization.items.armor; -import aztech.modern_industrialization.util.TextHelper; import io.github.ladysnake.pal.VanillaAbilities; -import java.util.List; -import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.Entity; @@ -36,14 +33,12 @@ import net.minecraft.world.item.ArmorMaterial; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Rarity; -import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.Wearable; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; -import team.reborn.energy.api.base.SimpleBatteryItem; +import team.reborn.energy.api.base.SimpleEnergyItem; -public class GraviChestPlateItem extends ArmorItem implements Wearable, ActivatableChestItem, SimpleBatteryItem { +public class GraviChestPlateItem extends ArmorItem implements Wearable, ActivatableChestItem, SimpleEnergyItem { public GraviChestPlateItem(Properties settings) { super(buildMaterial(), EquipmentSlot.CHEST, settings.stacksTo(1).rarity(Rarity.EPIC)); } @@ -119,11 +114,6 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotI } } - @Override - public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltip, TooltipFlag context) { - tooltip.add(TextHelper.getEuTextMaxed(getEnergy(stack), ENERGY_CAPACITY, true)); - } - @Override public boolean isBarVisible(ItemStack stack) { return true; @@ -135,17 +125,17 @@ public int getBarWidth(ItemStack stack) { } @Override - public long getEnergyCapacity() { + public long getEnergyCapacity(ItemStack stack) { return ENERGY_CAPACITY; } @Override - public long getEnergyMaxInput() { + public long getEnergyMaxInput(ItemStack stack) { return ENERGY_CAPACITY; } @Override - public long getEnergyMaxOutput() { + public long getEnergyMaxOutput(ItemStack stack) { return 0; } } diff --git a/src/main/java/aztech/modern_industrialization/machines/blockentities/AbstractStorageMachineBlockEntity.java b/src/main/java/aztech/modern_industrialization/machines/blockentities/AbstractStorageMachineBlockEntity.java index f7847e552..d61bb556a 100644 --- a/src/main/java/aztech/modern_industrialization/machines/blockentities/AbstractStorageMachineBlockEntity.java +++ b/src/main/java/aztech/modern_industrialization/machines/blockentities/AbstractStorageMachineBlockEntity.java @@ -47,7 +47,6 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.BlockEntityType; -import team.reborn.energy.api.EnergyStorage; public abstract class AbstractStorageMachineBlockEntity extends MachineBlockEntity implements Tickable, EnergyComponentHolder { @@ -116,21 +115,40 @@ public EnergyComponent getEnergyComponent() { @Override protected InteractionResult onUse(Player player, InteractionHand hand, Direction face) { - var energyItem = ContainerItemContext.ofPlayerHand(player, hand).find(EnergyStorage.ITEM); + var energyItem = ContainerItemContext.ofPlayerHand(player, hand).find(EnergyApi.ITEM); if (energyItem != null) { if (!player.level.isClientSide()) { + boolean insertedSomething = false; + for (int i = 0; i < 10000; ++i) { // Try up to 10000 times to bypass I/O limits try (Transaction transaction = Transaction.openOuter()) { long inserted = energyItem.insert(energy.getEu(), transaction); if (inserted == 0) { break; + } else { + insertedSomething = true; } energy.consumeEu(inserted, Simulation.ACT); transaction.commit(); } } + + if (!insertedSomething) { + for (int i = 0; i < 10000; ++i) { // Try up to 10000 times to bypass I/O limits + try (Transaction transaction = Transaction.openOuter()) { + long extracted = energyItem.extract(energy.getRemainingCapacity(), transaction); + + if (extracted == 0) { + break; + } + + energy.insertEu(extracted, Simulation.ACT); + transaction.commit(); + } + } + } } return InteractionResult.sidedSuccess(player.level.isClientSide()); } diff --git a/src/main/java/aztech/modern_industrialization/materials/MIMaterials.java b/src/main/java/aztech/modern_industrialization/materials/MIMaterials.java index 821662ea2..9254cebac 100644 --- a/src/main/java/aztech/modern_industrialization/materials/MIMaterials.java +++ b/src/main/java/aztech/modern_industrialization/materials/MIMaterials.java @@ -246,7 +246,7 @@ public static MaterialBuilder addVanillaGem(boolean compressor, String gemPath, .set(MaterialProperty.SET, STONE) .set(MaterialProperty.MEAN_RGB, 0xd20000) .set(MaterialProperty.HARDNESS, SOFT) - .addParts(TINY_DUST, CRUSHED_DUST, BATTERY).addMaterialItemParts(MaterialItemPart.external(DUST, "minecraft:redstone", "minecraft:redstone")) + .addParts(TINY_DUST, CRUSHED_DUST, BATTERY.of(CableTier.LV)).addMaterialItemParts(MaterialItemPart.external(DUST, "minecraft:redstone", "minecraft:redstone")) .addMaterialItemParts(MaterialItemPart.external(BLOCK, "#c:redstone_blocks", "minecraft:redstone_block")) .addMaterialItemParts(MaterialItemPart.external(ORE, "#c:redstone_ores", "minecraft:redstone_ore")) .addMaterialItemParts(MaterialItemPart.external(ORE_DEEPSLATE, "#c:redstone_ores", "minecraft:deepslate_redstone_ore")) @@ -431,7 +431,7 @@ public static MaterialBuilder addVanillaGem(boolean compressor, String gemPath, .set(MaterialProperty.SET, STONE) .set(MaterialProperty.MEAN_RGB, 0x071CB8) .set(MaterialProperty.HARDNESS, SOFT).addParts(TINY_DUST, DUST).addParts(BLOCK.of(MaterialBlockSet.LAPIS)) - .addParts(BATTERY).addRecipes(StandardRecipes::apply, SmeltingRecipes::apply)); + .addParts(BATTERY.of(CableTier.HV)).addRecipes(StandardRecipes::apply, SmeltingRecipes::apply)); SALT = MaterialRegistry.addMaterial(new MaterialBuilder("Salt", "salt") .set(MaterialProperty.MAIN_PART, DUST) @@ -469,7 +469,7 @@ public static MaterialBuilder addVanillaGem(boolean compressor, String gemPath, .set(MaterialProperty.MEAN_RGB, 0x3C3C50) .set(MaterialProperty.HARDNESS, SOFT) .addParts(ITEM_PURE_METAL) - .addParts(BLOCK.of(MaterialBlockSet.IRON)).addParts(N_DOPED_PLATE, P_DOPED_PLATE).addParts(PLATE, DOUBLE_INGOT, BATTERY) + .addParts(BLOCK.of(MaterialBlockSet.IRON)).addParts(N_DOPED_PLATE, P_DOPED_PLATE).addParts(PLATE, DOUBLE_INGOT, BATTERY.of(CableTier.MV)) .addRecipes(StandardRecipes::apply, SmeltingRecipes::apply)); STAINLESS_STEEL = MaterialRegistry.addMaterial(new MaterialBuilder("Stainless Steel", "stainless_steel") @@ -597,7 +597,7 @@ public static MaterialBuilder addVanillaGem(boolean compressor, String gemPath, .set(MaterialProperty.SET, SHINY) .set(MaterialProperty.MEAN_RGB, 0xd701e7) .set(MaterialProperty.HARDNESS, VERY_HARD).addParts(BLOCK.of(MaterialBlockSet.GOLD)) - .addParts(ITEM_PURE_METAL).addParts(BATTERY).addRecipes(StandardRecipes::apply) + .addParts(ITEM_PURE_METAL).addParts(BATTERY.of(CableTier.SUPERCONDUCTOR)).addRecipes(StandardRecipes::apply) .addRecipes((ctx) -> SmeltingRecipes.applyBlastFurnace(ctx, 128))); PLATINUM = MaterialRegistry.addMaterial( @@ -658,7 +658,7 @@ public static MaterialBuilder addVanillaGem(boolean compressor, String gemPath, .set(MaterialProperty.SET, DULL) .set(MaterialProperty.MEAN_RGB, 0x967224) .set(MaterialProperty.HARDNESS, SOFT) - .addParts(DUST, TINY_DUST, INGOT, PLATE, ROD, DOUBLE_INGOT, BATTERY) + .addParts(DUST, TINY_DUST, INGOT, PLATE, ROD, DOUBLE_INGOT, BATTERY.of(CableTier.EV)) .addParts( new PartTemplate("Control Rod", FUEL_ROD.key) .withRegister((partContext, part, itemPath1, itemId, itemTag, englishName) -> NuclearAbsorbable diff --git a/src/main/java/aztech/modern_industrialization/materials/part/BatteryPart.java b/src/main/java/aztech/modern_industrialization/materials/part/BatteryPart.java new file mode 100644 index 000000000..64c6682a5 --- /dev/null +++ b/src/main/java/aztech/modern_industrialization/materials/part/BatteryPart.java @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Copyright (c) 2020 Azercoco & Technici4n + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package aztech.modern_industrialization.materials.part; + +import aztech.modern_industrialization.api.energy.CableTier; +import aztech.modern_industrialization.items.PortableStorageUnit; + +public class BatteryPart implements PartKeyProvider { + + @Override + public PartKey key() { + return new PartKey("battery"); + } + + public PartTemplate of(long batteryCapacity) { + return new PartTemplate("Battery", "battery").withRegister( + (partContext, part, itemPath, itemId, itemTag, englishName) -> { + var item = PartTemplate.createSimpleItem(englishName, itemPath, partContext, part); + PortableStorageUnit.CAPACITY_PER_BATTERY.put(item, batteryCapacity); + }); + } + + public PartTemplate of(CableTier tier) { + return of(60 * 20 * tier.getMaxTransfer()); + } +} diff --git a/src/main/java/aztech/modern_industrialization/materials/part/MIParts.java b/src/main/java/aztech/modern_industrialization/materials/part/MIParts.java index ad395df7e..34ef04627 100644 --- a/src/main/java/aztech/modern_industrialization/materials/part/MIParts.java +++ b/src/main/java/aztech/modern_industrialization/materials/part/MIParts.java @@ -33,7 +33,7 @@ public class MIParts { - public static final PartTemplate BATTERY = new PartTemplate("Battery", "battery"); + public static final BatteryPart BATTERY = new BatteryPart(); public static final BarrelPart BARREL = new BarrelPart(); public static final PartTemplate BLADE = new PartTemplate("Blade", "blade"); public static final BlockPart BLOCK = new BlockPart(); diff --git a/src/main/java/aztech/modern_industrialization/util/TextHelper.java b/src/main/java/aztech/modern_industrialization/util/TextHelper.java index 0e3d76c06..2abcad667 100644 --- a/src/main/java/aztech/modern_industrialization/util/TextHelper.java +++ b/src/main/java/aztech/modern_industrialization/util/TextHelper.java @@ -83,7 +83,7 @@ public static Amount getAmountGeneric(Number number) { } public static Amount getAmount(double amount) { - if (amount < 10000) { + if (amount < 100000) { return new Amount(getAmount(amount, 1), ""); } else { int i = 0; @@ -95,7 +95,7 @@ public static Amount getAmount(double amount) { } public static MaxedAmount getMaxedAmount(double amount, double max) { - if (max < 10000) { + if (max < 100000) { return new MaxedAmount(getAmount(amount, 1), getAmount(max, 1), ""); } else { int i = 0; @@ -106,8 +106,21 @@ public static MaxedAmount getMaxedAmount(double amount, double max) { } } + public static MaxedAmount getMaxedAmountGeneric(Number amount, Number max) { + if (amount instanceof Long l && max instanceof Long m) { + return getMaxedAmount(l, m); + } else if (amount instanceof Integer i && max instanceof Integer m) { + return getMaxedAmount(i, m); + } else if (amount instanceof Double d && max instanceof Double m) { + return getMaxedAmount(d, m); + } else if (amount instanceof Float f && max instanceof Float m) { + return getMaxedAmount(f, m); + } + throw new IllegalArgumentException("Number " + amount + " or " + max + " is neither long, int, double or float"); + } + public static Amount getAmount(long amount) { - if (amount < 10000) { + if (amount < 100000) { return new Amount(String.valueOf(amount), ""); } else { int i = 0; @@ -119,7 +132,7 @@ public static Amount getAmount(long amount) { } public static MaxedAmount getMaxedAmount(long amount, long max) { - if (max < 10000) { + if (max < 100000) { return new MaxedAmount(String.valueOf(amount), String.valueOf(max), ""); } else { int i = 0; @@ -130,8 +143,8 @@ public static MaxedAmount getMaxedAmount(long amount, long max) { } } - public static MutableComponent getEuTextMaxed(long eu, long max) { - var amount = getMaxedAmount(eu, max); + public static MutableComponent getEuTextMaxed(Number eu, Number max) { + var amount = getMaxedAmountGeneric(eu, max); return MIText.EuMaxed.text(amount.digit(), amount.maxDigit(), amount.unit()); } @@ -167,12 +180,4 @@ public static Component getEuTextTick(double eu, boolean style) { return text; } - public static MutableComponent getEuTextMaxed(long eu, long max, boolean style) { - MutableComponent text = getEuTextMaxed(eu, max); - if (style) { - text.setStyle(TextHelper.NUMBER_TEXT); - } - return text; - } - } diff --git a/src/main/resources/assets/modern_industrialization/textures/item/portable_storage_unit.png b/src/main/resources/assets/modern_industrialization/textures/item/portable_storage_unit.png new file mode 100644 index 0000000000000000000000000000000000000000..08a1089d3804d1ea76b5f63f033b86ef7ca7aa37 GIT binary patch literal 2257 zcmV;?2rl=DP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+TB)LmLw?%{dX0!1Of4}9G~a(4rcjt4K*sOvL4wz z^EDYKLjnN%M7ADIte~6KDn(Z^+os;!=tN(*I2jU<;wm` zxK!Ut=C^rdxPT}%g_JONA+gunEe~Y=MKZ>Cy%lmK;iB1K5NKSUARzCycL&fu2IyUo z4`n_^|E4|!pY!I+hgkX@BM_fXkbWNgE5r|m<@Si*PXPAtw4MDQqs1}$+Ff=Y5%oKx ztU1w{Yamz3avjg6aL0Y1-$-#+9IQWXg573PQyW?PnuqV$$qa^WnHQ;h3W zkO^%oK!{*l;S327u%1N8lMT#)2yu)6D8q9W#{~$GDmOUEPQb(zs7P%ZGxS+v@5MoFnM~Nq) zM&nDk@lVK^3Eh8zoB?#txP5|Jn|-cch^GbZ+HYEn#`q>8xGFnGtUP1N2B@E zg?5OW1ea!|$7qHt>$?u=!F?h2h14xg&8&GZz0{{^&uf+t!+*cEVaHO}N9{VL+PQ6?W~VMzAX#U1qvT{^+zf5f|zfI_l2V|Ek##4&>a~x$2a)+!1olu z4`Sv;xhb-PCZkZI5uD4M&yTxS-Ca9&p;%W+V-bx9Y+R$>u`MH19r_B6JCq z$9*(&9C8nLnN+AULE< z(oDE3;BNI)9+hLX_GL7&Yde$?Cxs4~!+orq(NjiuY6ziN${}69TX?>fXNS(0cLzob z?8BbSKE3nR5xsxw0WR(6v1Vs{!PWjvH0>KijZ*bB3nu=yOaEgC*an{wrRS*O}KwMp%6kVjm|0RVMu^t@vE_mzb%?Q;TVI9AEeF@bxajvpS#qbMz=V zlK~!)c#i3YMZ7^gvuWv^_lZNSC@I9}#G?jXkob}7vdeFr3l0lBGi0Qb^TZ)yvCzhH z8?&OJ5>F9_6;-2rA>*>bd5g1JuCnGm`3r+NZ6(EZnnQ?T32`JKLPixOlwl!4t44~6 zB<)8#_y-+-f?P7WN?_zzKm{r!#}EDozq>W_lM`-IFbeoyZ2Myv@b3bRnr(j{+jipw z@IC`qTFYOl1GAr`*IHWm2rOF=Jay{)dV8OqbIyC@HP*pj>87@5|fSp~WME_Y&`M+M7$OO8^Kgp#b7Mv4kQu&*FjM4HY+W z0)#83sGE$^=#K(0)RK?e$Ryg_2S7o8CvGD%q3){