From 52f68e0a24fc2ff02f79f94aac8ca9fd7ec56ff0 Mon Sep 17 00:00:00 2001
From: Ghzdude <44148655+ghzdude@users.noreply.github.com>
Date: Wed, 18 Sep 2024 20:58:37 -0700
Subject: [PATCH 1/7] Make Ender Cover and Virtual Registry Abstract (#2510)
---
.../java/gregtech/api/mui/GTGuiTextures.java | 2 +
src/main/java/gregtech/api/mui/GTGuis.java | 11 +-
.../api/mui/sync/GTFluidSyncHandler.java | 224 ++++++++
.../api/util/FluidTankSwitchShim.java | 21 +-
.../api/util/VirtualTankRegistry.java | 338 ------------
.../api/util/virtualregistry/EntryTypes.java | 66 +++
.../virtualregistry/VirtualEnderRegistry.java | 175 ++++++
.../util/virtualregistry/VirtualEntry.java | 79 +++
.../virtualregistry/VirtualRegistryMap.java | 87 +++
.../virtualregistry/entries/VirtualTank.java | 180 ++++++
.../java/gregtech/common/EventHandlers.java | 4 +-
.../common/covers/CoverBehaviors.java | 1 +
.../common/covers/CoverEnderFluidLink.java | 348 ------------
.../covers/ender/CoverAbstractEnderLink.java | 513 ++++++++++++++++++
.../covers/ender/CoverEnderFluidLink.java | 193 +++++++
.../common/mui/widget/GTFluidSlot.java | 142 +++++
.../common/mui/widget/InteractableText.java | 63 +++
.../common/terminal/app/VirtualTankApp.java | 12 +-
src/main/java/gregtech/core/CoreModule.java | 4 +-
.../drivers/DriverCoverHolder.java | 1 +
.../values/ValueCoverEnderFluidLink.java | 2 +-
.../provider/CoverInfoProvider.java | 5 +-
.../resources/assets/gregtech/lang/en_us.lang | 7 +
.../textures/gui/overlay/menu_overlay.png | Bin 0 -> 130 bytes
24 files changed, 1772 insertions(+), 706 deletions(-)
create mode 100644 src/main/java/gregtech/api/mui/sync/GTFluidSyncHandler.java
delete mode 100644 src/main/java/gregtech/api/util/VirtualTankRegistry.java
create mode 100644 src/main/java/gregtech/api/util/virtualregistry/EntryTypes.java
create mode 100644 src/main/java/gregtech/api/util/virtualregistry/VirtualEnderRegistry.java
create mode 100644 src/main/java/gregtech/api/util/virtualregistry/VirtualEntry.java
create mode 100644 src/main/java/gregtech/api/util/virtualregistry/VirtualRegistryMap.java
create mode 100644 src/main/java/gregtech/api/util/virtualregistry/entries/VirtualTank.java
delete mode 100644 src/main/java/gregtech/common/covers/CoverEnderFluidLink.java
create mode 100644 src/main/java/gregtech/common/covers/ender/CoverAbstractEnderLink.java
create mode 100644 src/main/java/gregtech/common/covers/ender/CoverEnderFluidLink.java
create mode 100644 src/main/java/gregtech/common/mui/widget/GTFluidSlot.java
create mode 100644 src/main/java/gregtech/common/mui/widget/InteractableText.java
create mode 100644 src/main/resources/assets/gregtech/textures/gui/overlay/menu_overlay.png
diff --git a/src/main/java/gregtech/api/mui/GTGuiTextures.java b/src/main/java/gregtech/api/mui/GTGuiTextures.java
index f17affee609..4f0345f49fc 100644
--- a/src/main/java/gregtech/api/mui/GTGuiTextures.java
+++ b/src/main/java/gregtech/api/mui/GTGuiTextures.java
@@ -206,6 +206,8 @@ public static class IDs {
"textures/gui/widget/button_public_private.png",
18, 36, 18, 18, true);
+ public static final UITexture MENU_OVERLAY = fullImage("textures/gui/overlay/menu_overlay.png");
+
// todo bronze/steel/primitive fluid slots?
// SLOT OVERLAYS
diff --git a/src/main/java/gregtech/api/mui/GTGuis.java b/src/main/java/gregtech/api/mui/GTGuis.java
index b5599dd9cfd..614f6a08f1b 100644
--- a/src/main/java/gregtech/api/mui/GTGuis.java
+++ b/src/main/java/gregtech/api/mui/GTGuis.java
@@ -9,6 +9,7 @@
import net.minecraft.item.ItemStack;
+import com.cleanroommc.modularui.api.widget.Interactable;
import com.cleanroommc.modularui.factory.GuiManager;
import com.cleanroommc.modularui.screen.ModularPanel;
import com.cleanroommc.modularui.utils.Alignment;
@@ -62,7 +63,15 @@ public PopupPanel(@NotNull String name, int width, int height, boolean disableBe
super(name);
size(width, height).align(Alignment.Center);
background(GTGuiTextures.BACKGROUND_POPUP);
- child(ButtonWidget.panelCloseButton().top(5).right(5));
+ child(ButtonWidget.panelCloseButton().top(5).right(5)
+ .onMousePressed(mouseButton -> {
+ if (mouseButton == 0 || mouseButton == 1) {
+ this.closeIfOpen(true);
+ Interactable.playButtonClickSound();
+ return true;
+ }
+ return false;
+ }));
this.disableBelow = disableBelow;
this.closeOnOutsideClick = closeOnOutsideClick;
}
diff --git a/src/main/java/gregtech/api/mui/sync/GTFluidSyncHandler.java b/src/main/java/gregtech/api/mui/sync/GTFluidSyncHandler.java
new file mode 100644
index 00000000000..b5be013da18
--- /dev/null
+++ b/src/main/java/gregtech/api/mui/sync/GTFluidSyncHandler.java
@@ -0,0 +1,224 @@
+package gregtech.api.mui.sync;
+
+import gregtech.api.util.GTUtility;
+
+import net.minecraft.entity.item.EntityItem;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.util.SoundCategory;
+import net.minecraft.util.SoundEvent;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.IFluidTank;
+import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
+import net.minecraftforge.fluids.capability.IFluidHandlerItem;
+
+import com.cleanroommc.modularui.network.NetworkUtils;
+import com.cleanroommc.modularui.value.sync.SyncHandler;
+import org.jetbrains.annotations.NotNull;
+
+public class GTFluidSyncHandler extends SyncHandler {
+
+ private static final int TRY_CLICK_CONTAINER = 1;
+
+ private final IFluidTank tank;
+ private boolean canDrainSlot = true;
+ private boolean canFillSlot = true;
+
+ public GTFluidSyncHandler(IFluidTank tank) {
+ this.tank = tank;
+ }
+
+ public FluidStack getFluid() {
+ return this.tank.getFluid();
+ }
+
+ public int getCapacity() {
+ return this.tank.getCapacity();
+ }
+
+ public GTFluidSyncHandler canDrainSlot(boolean canDrainSlot) {
+ this.canDrainSlot = canDrainSlot;
+ return this;
+ }
+
+ public boolean canDrainSlot() {
+ return this.canDrainSlot;
+ }
+
+ public GTFluidSyncHandler canFillSlot(boolean canFillSlot) {
+ this.canFillSlot = canFillSlot;
+ return this;
+ }
+
+ public boolean canFillSlot() {
+ return this.canFillSlot;
+ }
+
+ @Override
+ public void readOnClient(int id, PacketBuffer buf) {
+ if (id == TRY_CLICK_CONTAINER) {
+ replaceCursorItemStack(NetworkUtils.readItemStack(buf));
+ }
+ }
+
+ @Override
+ public void readOnServer(int id, PacketBuffer buf) {
+ if (id == TRY_CLICK_CONTAINER) {
+ var stack = tryClickContainer(buf.readBoolean());
+ if (!stack.isEmpty())
+ syncToClient(TRY_CLICK_CONTAINER, buffer -> NetworkUtils.writeItemStack(buffer, stack));
+ }
+ }
+
+ public ItemStack tryClickContainer(boolean tryFillAll) {
+ ItemStack playerHeldStack = getSyncManager().getCursorItem();
+ if (playerHeldStack.isEmpty())
+ return ItemStack.EMPTY;
+
+ ItemStack useStack = GTUtility.copy(1, playerHeldStack);
+ IFluidHandlerItem fluidHandlerItem = useStack
+ .getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null);
+ if (fluidHandlerItem == null) return ItemStack.EMPTY;
+
+ FluidStack tankFluid = tank.getFluid();
+ FluidStack heldFluid = fluidHandlerItem.drain(Integer.MAX_VALUE, false);
+
+ // nothing to do, return
+ if (tankFluid == null && heldFluid == null)
+ return ItemStack.EMPTY;
+
+ // tank is empty, try to fill tank
+ if (canFillSlot && tankFluid == null) {
+ return fillTankFromStack(fluidHandlerItem, heldFluid, tryFillAll);
+
+ // hand is empty, try to drain tank
+ } else if (canDrainSlot && heldFluid == null) {
+ return drainTankFromStack(fluidHandlerItem, tankFluid, tryFillAll);
+
+ // neither is empty but tank is not full, try to fill tank
+ } else if (canFillSlot && tank.getFluidAmount() < tank.getCapacity() && heldFluid != null) {
+ return fillTankFromStack(fluidHandlerItem, heldFluid, tryFillAll);
+ }
+
+ return ItemStack.EMPTY;
+ }
+
+ private ItemStack fillTankFromStack(IFluidHandlerItem fluidHandler, @NotNull FluidStack heldFluid,
+ boolean tryFillAll) {
+ ItemStack heldItem = getSyncManager().getCursorItem();
+ if (heldItem.isEmpty()) return ItemStack.EMPTY;
+
+ FluidStack currentFluid = tank.getFluid();
+ // Fluid type does not match
+ if (currentFluid != null && !currentFluid.isFluidEqual(heldFluid)) return ItemStack.EMPTY;
+
+ int freeSpace = tank.getCapacity() - tank.getFluidAmount();
+ if (freeSpace <= 0) return ItemStack.EMPTY;
+
+ ItemStack itemStackEmptied = ItemStack.EMPTY;
+ int fluidAmountTaken = 0;
+
+ FluidStack drained = fluidHandler.drain(freeSpace, true);
+ if (drained != null && drained.amount > 0) {
+ itemStackEmptied = fluidHandler.getContainer();
+ fluidAmountTaken = drained.amount;
+ }
+ if (itemStackEmptied == ItemStack.EMPTY) {
+ return ItemStack.EMPTY;
+ }
+
+ // find out how many fills we can do
+ // same round down behavior as drain
+ int additional = tryFillAll ? Math.min(freeSpace / fluidAmountTaken, heldItem.getCount()) : 1;
+ FluidStack copiedFluidStack = heldFluid.copy();
+ copiedFluidStack.amount = fluidAmountTaken * additional;
+ tank.fill(copiedFluidStack, true);
+
+ itemStackEmptied.setCount(additional);
+ replaceCursorItemStack(itemStackEmptied);
+ playSound(heldFluid, true);
+ return itemStackEmptied;
+ }
+
+ private ItemStack drainTankFromStack(IFluidHandlerItem fluidHandler, FluidStack tankFluid, boolean tryFillAll) {
+ ItemStack heldItem = getSyncManager().getCursorItem();
+ if (heldItem.isEmpty()) return ItemStack.EMPTY;
+
+ ItemStack fluidContainer = fluidHandler.getContainer();
+ int filled = fluidHandler.fill(tankFluid, false);
+ if (filled > 0) {
+ tank.drain(filled, true);
+ fluidHandler.fill(tankFluid, true);
+ if (tryFillAll) {
+ // Determine how many more items we can fill. One item is already filled.
+ // Integer division means it will round down, so it will only fill equivalent fluid amounts.
+ // For example:
+ // Click with 3 cells, with 2500L of fluid in the tank.
+ // 2 cells will be filled, and 500L will be left behind in the tank.
+ int additional = Math.min(heldItem.getCount(), tankFluid.amount / filled) - 1;
+ tank.drain(filled * additional, true);
+ fluidContainer.grow(additional);
+ }
+ replaceCursorItemStack(fluidContainer);
+ playSound(tankFluid, false);
+ return fluidContainer;
+ }
+ return ItemStack.EMPTY;
+ }
+
+ /**
+ * Replace the ItemStack on the player's cursor with the passed stack. Use to replace empty cells with filled, or
+ * filled cells with empty. If it is not fully emptied/filled, it will place the new items into the player inventory
+ * instead, and shrink the held stack by the appropriate amount.
+ */
+ private void replaceCursorItemStack(ItemStack resultStack) {
+ int resultStackSize = resultStack.getMaxStackSize();
+ ItemStack playerStack = getSyncManager().getCursorItem();
+
+ if (!getSyncManager().isClient())
+ syncToClient(TRY_CLICK_CONTAINER, buffer -> NetworkUtils.writeItemStack(buffer, resultStack));
+
+ while (resultStack.getCount() > resultStackSize) {
+ playerStack.shrink(resultStackSize);
+ addItemToPlayerInventory(resultStack.splitStack(resultStackSize));
+ }
+ if (playerStack.getCount() == resultStack.getCount()) {
+ // every item on the cursor is mutated, so leave it there
+ getSyncManager().setCursorItem(resultStack);
+ } else {
+ // some items not mutated. Mutated items go into the inventory/world.
+ playerStack.shrink(resultStack.getCount());
+ getSyncManager().setCursorItem(playerStack);
+ addItemToPlayerInventory(resultStack);
+ }
+ }
+
+ /** Place an item into the player's inventory, or drop it in-world as an item entity if it cannot fit. */
+ private void addItemToPlayerInventory(ItemStack stack) {
+ if (stack == null) return;
+ var player = getSyncManager().getPlayer();
+
+ if (!player.inventory.addItemStackToInventory(stack) && !player.world.isRemote) {
+ EntityItem dropItem = player.entityDropItem(stack, 0);
+ if (dropItem != null) dropItem.setPickupDelay(0);
+ }
+ }
+
+ /**
+ * Play the appropriate fluid interaction sound for the fluid.
+ * Must be called on server to work correctly
+ **/
+ private void playSound(FluidStack fluid, boolean fill) {
+ if (fluid == null) return;
+ SoundEvent soundEvent;
+ if (fill) {
+ soundEvent = fluid.getFluid().getFillSound(fluid);
+ } else {
+ soundEvent = fluid.getFluid().getEmptySound(fluid);
+ }
+ EntityPlayer player = getSyncManager().getPlayer();
+ player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ,
+ soundEvent, SoundCategory.PLAYERS, 1.0F, 1.0F);
+ }
+}
diff --git a/src/main/java/gregtech/api/util/FluidTankSwitchShim.java b/src/main/java/gregtech/api/util/FluidTankSwitchShim.java
index e0210eee145..0e4c556da3a 100644
--- a/src/main/java/gregtech/api/util/FluidTankSwitchShim.java
+++ b/src/main/java/gregtech/api/util/FluidTankSwitchShim.java
@@ -11,14 +11,17 @@
// probably causes problems
public class FluidTankSwitchShim implements IFluidTank, IFluidHandler {
- IFluidTank tank;
+ @Nullable
+ private IFluidTank tank;
+ private static final FluidTankInfo NO_INFO = new FluidTankInfo(null, 0);
+ private static final IFluidTankProperties[] NO_PROPS = new IFluidTankProperties[0];
public FluidTankSwitchShim(IFluidTank tank) {
changeTank(tank);
}
public void changeTank(IFluidTank tank) {
- if (!(tank instanceof IFluidHandler)) {
+ if (tank != null && !(tank instanceof IFluidHandler)) {
throw new IllegalArgumentException("Shim tank must be both IFluidTank and IFluidHandler!");
}
this.tank = tank;
@@ -27,43 +30,49 @@ public void changeTank(IFluidTank tank) {
@Nullable
@Override
public FluidStack getFluid() {
- return tank.getFluid();
+ return tank == null ? null : tank.getFluid();
}
@Override
public int getFluidAmount() {
- return tank.getFluidAmount();
+ return tank == null ? 0 : tank.getFluidAmount();
}
@Override
public int getCapacity() {
- return tank.getCapacity();
+ return tank == null ? 0 : tank.getCapacity();
}
@Override
public FluidTankInfo getInfo() {
- return tank.getInfo();
+ return tank == null ? NO_INFO : tank.getInfo();
}
@Override
public IFluidTankProperties[] getTankProperties() {
+ if (tank == null)
+ return NO_PROPS;
+
return ((IFluidHandler) tank).getTankProperties();
}
@Override
public int fill(FluidStack resource, boolean doFill) {
+ if (tank == null) return 0;
return ((IFluidHandler) tank).fill(resource, doFill);
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain) {
+ if (tank == null) return null;
return ((IFluidHandler) tank).drain(resource, doDrain);
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain) {
+ if (tank == null) return null;
return tank.drain(maxDrain, doDrain);
}
}
diff --git a/src/main/java/gregtech/api/util/VirtualTankRegistry.java b/src/main/java/gregtech/api/util/VirtualTankRegistry.java
deleted file mode 100644
index f43809d7eb3..00000000000
--- a/src/main/java/gregtech/api/util/VirtualTankRegistry.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package gregtech.api.util;
-
-import gregtech.api.GTValues;
-
-import net.minecraft.nbt.NBTTagCompound;
-import net.minecraft.world.World;
-import net.minecraft.world.storage.MapStorage;
-import net.minecraft.world.storage.WorldSavedData;
-import net.minecraftforge.fluids.FluidStack;
-import net.minecraftforge.fluids.FluidTankInfo;
-import net.minecraftforge.fluids.IFluidTank;
-import net.minecraftforge.fluids.capability.IFluidHandler;
-import net.minecraftforge.fluids.capability.IFluidTankProperties;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-public class VirtualTankRegistry extends WorldSavedData {
-
- private static final int DEFAULT_CAPACITY = 64000; // 64B
- private static final String DATA_ID = GTValues.MODID + ".vtank_data";
-
- protected static Map> tankMap = new HashMap<>();
-
- public VirtualTankRegistry() {
- super(DATA_ID);
- }
-
- // for some reason, MapStorage throws an error if this constructor is not present
- @SuppressWarnings("unused")
- public VirtualTankRegistry(String name) {
- super(name);
- }
-
- /**
- * Retrieves a tank from the registry
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- * @return The tank object
- */
- public static IFluidTank getTank(String key, UUID uuid) {
- return tankMap.get(uuid).get(key);
- }
-
- /**
- * @return the internal Map of tanks.
- * Do not use to modify the map!
- */
- public static Map> getTankMap() {
- return tankMap;
- }
-
- /**
- * Retrieves a tank from the registry, creating it if it does not exist
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- * @param capacity The initial capacity of the tank
- * @return The tank object
- */
- public static IFluidTank getTankCreate(String key, UUID uuid, int capacity) {
- if (!tankMap.containsKey(uuid) || !tankMap.get(uuid).containsKey(key)) {
- addTank(key, uuid, capacity);
- }
- return getTank(key, uuid);
- }
-
- /**
- * Retrieves a tank from the registry, creating it with {@link #DEFAULT_CAPACITY the default capacity} if it does
- * not exist
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- * @return The tank object
- */
- public static IFluidTank getTankCreate(String key, UUID uuid) {
- return getTankCreate(key, uuid, DEFAULT_CAPACITY);
- }
-
- /**
- * Adds a tank to the registry
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- * @param capacity The initial capacity of the tank
- */
- public static void addTank(String key, UUID uuid, int capacity) {
- if (tankMap.containsKey(uuid) && tankMap.get(uuid).containsKey(key)) {
- GTLog.logger.warn("Overwriting virtual tank " + key + "/" + (uuid == null ? "null" : uuid.toString()) +
- ", this might cause fluid loss!");
- } else if (!tankMap.containsKey(uuid)) {
- tankMap.put(uuid, new HashMap<>());
- }
- tankMap.get(uuid).put(key, new VirtualTank(capacity));
- }
-
- /**
- * Adds a tank to the registry with {@link #DEFAULT_CAPACITY the default capacity}
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- */
- public static void addTank(String key, UUID uuid) {
- addTank(key, uuid, DEFAULT_CAPACITY);
- }
-
- /**
- * Removes a tank from the registry. Use with caution!
- *
- * @param key The name of the tank
- * @param uuid The uuid of the player the tank is private to, or null if the tank is public
- * @param removeFluid Whether to remove the tank if it has fluid in it
- */
- public static void delTank(String key, UUID uuid, boolean removeFluid) {
- if (tankMap.containsKey(uuid) && tankMap.get(uuid).containsKey(key)) {
- if (removeFluid || tankMap.get(uuid).get(key).getFluidAmount() <= 0) {
- tankMap.get(uuid).remove(key);
- if (tankMap.get(uuid).size() == 0) {
- tankMap.remove(uuid);
- }
- }
- } else {
- GTLog.logger.warn("Attempted to delete tank " + key + "/" + (uuid == null ? "null" : uuid.toString()) +
- ", which does not exist!");
- }
- }
-
- /**
- * To be called on server stopped event
- */
- public static void clearMaps() {
- tankMap.clear();
- }
-
- @Override
- public void readFromNBT(NBTTagCompound nbt) {
- if (nbt.hasKey("Public")) {
- NBTTagCompound publicTanks = nbt.getCompoundTag("Public");
- for (String key : publicTanks.getKeySet()) {
- NBTTagCompound tankCompound = publicTanks.getCompoundTag(key);
- VirtualTankRegistry.addTank(key, null, tankCompound.getInteger("Capacity"));
- if (!tankCompound.hasKey("Empty")) {
- VirtualTankRegistry.getTank(key, null).fill(FluidStack.loadFluidStackFromNBT(tankCompound), true);
- }
- }
- }
- if (nbt.hasKey("Private")) {
- NBTTagCompound privateTankUUIDs = nbt.getCompoundTag("Private");
- for (String uuidStr : privateTankUUIDs.getKeySet()) {
- UUID uuid = UUID.fromString(uuidStr);
- NBTTagCompound privateTanks = privateTankUUIDs.getCompoundTag(uuidStr);
- for (String key : privateTanks.getKeySet()) {
- NBTTagCompound tankCompound = privateTanks.getCompoundTag(key);
- VirtualTankRegistry.addTank(key, uuid, tankCompound.getInteger("Capacity"));
- if (!tankCompound.hasKey("Empty")) {
- VirtualTankRegistry.getTank(key, uuid).fill(FluidStack.loadFluidStackFromNBT(tankCompound),
- true);
- }
- }
- }
- }
- }
-
- @NotNull
- @Override
- public NBTTagCompound writeToNBT(NBTTagCompound compound) {
- compound.setTag("Private", new NBTTagCompound());
- tankMap.forEach((uuid, map) -> {
- NBTTagCompound mapCompound = new NBTTagCompound();
- map.forEach((key, tank) -> {
- if (tank.getFluid() != null || tank.getCapacity() != DEFAULT_CAPACITY) {
- NBTTagCompound tankCompound = new NBTTagCompound();
- tankCompound.setInteger("Capacity", tank.getCapacity());
- if (tank.getFluid() != null) {
- tank.getFluid().writeToNBT(tankCompound);
- } else {
- tankCompound.setString("Empty", "");
- }
- mapCompound.setTag(key, tankCompound);
- }
- });
- if (mapCompound.getSize() > 0) {
- if (uuid == null) {
- compound.setTag("Public", mapCompound);
- } else {
- compound.getCompoundTag("Private").setTag(uuid.toString(), mapCompound);
- }
- }
- });
- return compound;
- }
-
- @Override
- public boolean isDirty() {
- // can't think of a good way to mark dirty other than always
- return true;
- }
-
- /**
- * To be called on world load event
- */
- public static void initializeStorage(World world) {
- MapStorage storage = world.getMapStorage();
- VirtualTankRegistry instance = (VirtualTankRegistry) storage.getOrLoadData(VirtualTankRegistry.class, DATA_ID);
-
- if (instance == null) {
- instance = new VirtualTankRegistry();
- storage.setData(DATA_ID, instance);
- }
- }
-
- private static class VirtualTank implements IFluidTank, IFluidHandler {
-
- @Nullable
- protected FluidStack fluid;
- protected int capacity;
- protected IFluidTankProperties[] tankProperties;
-
- public VirtualTank(int capacity) {
- this.capacity = capacity;
- }
-
- @Nullable
- @Override
- public FluidStack getFluid() {
- return this.fluid;
- }
-
- @Override
- public int getFluidAmount() {
- return this.fluid == null ? 0 : this.fluid.amount;
- }
-
- @Override
- public int getCapacity() {
- return this.capacity;
- }
-
- @Override
- public FluidTankInfo getInfo() {
- return new FluidTankInfo(this);
- }
-
- @Override
- public IFluidTankProperties[] getTankProperties() {
- if (this.tankProperties == null) {
- this.tankProperties = new IFluidTankProperties[] { new VirtualTankProperties(this) };
- }
- return this.tankProperties;
- }
-
- @Override
- public int fill(FluidStack fluidStack, boolean doFill) {
- if (fluidStack == null || fluidStack.amount <= 0 ||
- (this.fluid != null && !fluidStack.isFluidEqual(this.fluid)))
- return 0;
-
- int fillAmt = Math.min(fluidStack.amount, this.capacity - this.getFluidAmount());
- if (doFill) {
- if (this.fluid == null) {
- this.fluid = new FluidStack(fluidStack, fillAmt);
- } else {
- this.fluid.amount += fillAmt;
- }
- }
- return fillAmt;
- }
-
- @Nullable
- @Override
- public FluidStack drain(FluidStack resource, boolean doDrain) {
- return resource == null || !resource.isFluidEqual(this.fluid) ? null : drain(resource.amount, doDrain);
- }
-
- @Nullable
- @Override
- public FluidStack drain(int amount, boolean doDrain) {
- if (this.fluid == null || amount <= 0)
- return null;
-
- int drainAmt = Math.min(this.getFluidAmount(), amount);
- FluidStack drainedFluid = new FluidStack(fluid, drainAmt);
- if (doDrain) {
- this.fluid.amount -= drainAmt;
- if (this.fluid.amount <= 0) {
- this.fluid = null;
- }
- }
- return drainedFluid;
- }
-
- private static class VirtualTankProperties implements IFluidTankProperties {
-
- protected final VirtualTank tank;
-
- private VirtualTankProperties(VirtualTank tank) {
- this.tank = tank;
- }
-
- @Nullable
- @Override
- public FluidStack getContents() {
- FluidStack contents = tank.getFluid();
- return contents == null ? null : contents.copy();
- }
-
- @Override
- public int getCapacity() {
- return tank.getCapacity();
- }
-
- @Override
- public boolean canFill() {
- return true;
- }
-
- @Override
- public boolean canDrain() {
- return true;
- }
-
- @Override
- public boolean canFillFluidType(FluidStack fluidStack) {
- return true;
- }
-
- @Override
- public boolean canDrainFluidType(FluidStack fluidStack) {
- return true;
- }
- }
- }
-}
diff --git a/src/main/java/gregtech/api/util/virtualregistry/EntryTypes.java b/src/main/java/gregtech/api/util/virtualregistry/EntryTypes.java
new file mode 100644
index 00000000000..6324958b8c7
--- /dev/null
+++ b/src/main/java/gregtech/api/util/virtualregistry/EntryTypes.java
@@ -0,0 +1,66 @@
+package gregtech.api.util.virtualregistry;
+
+import gregtech.api.util.GTLog;
+import gregtech.api.util.virtualregistry.entries.VirtualTank;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.ResourceLocation;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import static gregtech.api.util.GTUtility.gregtechId;
+
+public final class EntryTypes {
+
+ private static final Map> TYPES_MAP = new Object2ObjectOpenHashMap<>();
+ public static final EntryTypes ENDER_FLUID = addEntryType(gregtechId("ender_fluid"), VirtualTank::new);
+ // ENDER_ITEM("ender_item", null),
+ // ENDER_ENERGY("ender_energy", null),
+ // ENDER_REDSTONE("ender_redstone", null);
+ private final ResourceLocation location;
+ private final Supplier factory;
+
+ private EntryTypes(ResourceLocation location, Supplier supplier) {
+ this.location = location;
+ this.factory = supplier;
+ }
+
+ public T createInstance(NBTTagCompound nbt) {
+ var entry = createInstance();
+ entry.deserializeNBT(nbt);
+ return entry;
+ }
+
+ public T createInstance() {
+ return factory.get();
+ }
+
+ @Override
+ public String toString() {
+ return this.location.toString();
+ }
+
+ @Nullable
+ public static EntryTypes extends VirtualEntry> fromString(String name) {
+ return TYPES_MAP.getOrDefault(gregtechId(name), null);
+ }
+
+ @Nullable
+ public static EntryTypes extends VirtualEntry> fromLocation(String location) {
+ return TYPES_MAP.getOrDefault(new ResourceLocation(location), null);
+ }
+
+ public static EntryTypes addEntryType(ResourceLocation location, Supplier supplier) {
+ var type = new EntryTypes<>(location, supplier);
+ if (!TYPES_MAP.containsKey(location)) {
+ TYPES_MAP.put(location, type);
+ } else {
+ GTLog.logger.warn("Entry \"{}\" is already registered!", location);
+ }
+ return type;
+ }
+}
diff --git a/src/main/java/gregtech/api/util/virtualregistry/VirtualEnderRegistry.java b/src/main/java/gregtech/api/util/virtualregistry/VirtualEnderRegistry.java
new file mode 100644
index 00000000000..3d8ccd78224
--- /dev/null
+++ b/src/main/java/gregtech/api/util/virtualregistry/VirtualEnderRegistry.java
@@ -0,0 +1,175 @@
+package gregtech.api.util.virtualregistry;
+
+import gregtech.api.GTValues;
+import gregtech.api.util.GTLog;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraft.world.storage.MapStorage;
+import net.minecraft.world.storage.WorldSavedData;
+import net.minecraftforge.fluids.IFluidTank;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Predicate;
+
+@SuppressWarnings("SameParameterValue")
+public class VirtualEnderRegistry extends WorldSavedData {
+
+ private static final String DATA_ID = GTValues.MODID + ".virtual_entry_data";
+ private static final String OLD_DATA_ID = GTValues.MODID + ".vtank_data";
+ private static final String PUBLIC_KEY = "Public";
+ private static final String PRIVATE_KEY = "Private";
+ private static final Map VIRTUAL_REGISTRIES = new HashMap<>();
+
+ public VirtualEnderRegistry(String name) {
+ super(name);
+ }
+
+ public static T getEntry(@Nullable UUID owner, EntryTypes type, String name) {
+ return getRegistry(owner).getEntry(type, name);
+ }
+
+ public static void addEntry(@Nullable UUID owner, String name, VirtualEntry entry) {
+ getRegistry(owner).addEntry(name, entry);
+ }
+
+ public static boolean hasEntry(@Nullable UUID owner, EntryTypes> type, String name) {
+ return getRegistry(owner).contains(type, name);
+ }
+
+ public static @NotNull T getOrCreateEntry(@Nullable UUID owner, EntryTypes type,
+ String name) {
+ if (!hasEntry(owner, type, name))
+ addEntry(owner, name, type.createInstance());
+
+ return getEntry(owner, type, name);
+ }
+
+ /**
+ * Removes an entry from the registry. Use with caution!
+ *
+ * @param owner The uuid of the player the entry is private to, or null if the entry is public
+ * @param type Type of the registry to remove from
+ * @param name The name of the entry
+ */
+ public static void deleteEntry(@Nullable UUID owner, EntryTypes> type, String name) {
+ var registry = getRegistry(owner);
+ if (registry.contains(type, name)) {
+ registry.deleteEntry(type, name);
+ return;
+ }
+ GTLog.logger.warn("Attempted to delete {} entry {} of type {}, which does not exist",
+ owner == null ? "public" : String.format("private [%s]", owner), name, type);
+ }
+
+ public static void deleteEntry(@Nullable UUID owner, EntryTypes type, String name,
+ Predicate shouldDelete) {
+ T entry = getEntry(owner, type, name);
+ if (entry != null && shouldDelete.test(entry))
+ deleteEntry(owner, type, name);
+ }
+
+ public static Set getEntryNames(UUID owner, EntryTypes> type) {
+ return getRegistry(owner).getEntryNames(type);
+ }
+
+ /**
+ * To be called on server stopped event
+ */
+ public static void clearMaps() {
+ VIRTUAL_REGISTRIES.clear();
+ }
+
+ private static VirtualRegistryMap getRegistry(UUID owner) {
+ return VIRTUAL_REGISTRIES.computeIfAbsent(owner, key -> new VirtualRegistryMap());
+ }
+
+ // remove if tank app is removed
+ public static Map> createTankMap() {
+ Map> map = new HashMap<>();
+ for (var uuid : VIRTUAL_REGISTRIES.keySet()) {
+ map.put(uuid, new HashMap<>());
+ for (var name : getEntryNames(uuid, EntryTypes.ENDER_FLUID)) {
+ map.get(uuid).put(name, getEntry(uuid, EntryTypes.ENDER_FLUID, name));
+ }
+ }
+ return map;
+ }
+
+ @Override
+ public final void readFromNBT(NBTTagCompound nbt) {
+ if (nbt.hasKey(PUBLIC_KEY)) {
+ VIRTUAL_REGISTRIES.put(null, new VirtualRegistryMap(nbt.getCompoundTag(PUBLIC_KEY)));
+ }
+ if (nbt.hasKey(PRIVATE_KEY)) {
+ NBTTagCompound privateEntries = nbt.getCompoundTag(PRIVATE_KEY);
+ for (String owner : privateEntries.getKeySet()) {
+ var privateMap = privateEntries.getCompoundTag(owner);
+ VIRTUAL_REGISTRIES.put(UUID.fromString(owner), new VirtualRegistryMap(privateMap));
+ }
+ }
+ }
+
+ @NotNull
+ @Override
+ public final NBTTagCompound writeToNBT(@NotNull NBTTagCompound tag) {
+ var privateTag = new NBTTagCompound();
+ for (var owner : VIRTUAL_REGISTRIES.keySet()) {
+ var mapTag = VIRTUAL_REGISTRIES.get(owner).serializeNBT();
+ if (owner != null) {
+ privateTag.setTag(owner.toString(), mapTag);
+ } else {
+ tag.setTag(PUBLIC_KEY, mapTag);
+ }
+ }
+ tag.setTag(PRIVATE_KEY, privateTag);
+ return tag;
+ }
+
+ @Override
+ public boolean isDirty() {
+ // can't think of a good way to mark dirty other than always
+ return true;
+ }
+
+ /**
+ * To be called on world load event
+ */
+ @SuppressWarnings("DataFlowIssue")
+ public static void initializeStorage(World world) {
+ MapStorage storage = world.getMapStorage();
+
+ VirtualEnderRegistry instance = (VirtualEnderRegistry) storage.getOrLoadData(VirtualEnderRegistry.class,
+ DATA_ID);
+ VirtualEnderRegistry old = (VirtualEnderRegistry) storage.getOrLoadData(VirtualEnderRegistry.class,
+ OLD_DATA_ID);
+
+ if (instance == null) {
+ instance = new VirtualEnderRegistry(DATA_ID);
+ storage.setData(DATA_ID, instance);
+ }
+
+ if (old != null) {
+ instance.readFromNBT(old.serializeNBT());
+ var file = world.getSaveHandler().getMapFileFromName(OLD_DATA_ID);
+ var split = file.getName().split("\\.");
+ var stringBuilder = new StringBuilder(split[0])
+ .append('.')
+ .append(split[1])
+ .append(".backup")
+ .append('.')
+ .append(split[2]);
+ if (file.renameTo(new File(file.getParent(), stringBuilder.toString()))) {
+ file.deleteOnExit();
+ GTLog.logger.warn("Moved Virtual Tank Data to new format, created backup!");
+ }
+ }
+ }
+}
diff --git a/src/main/java/gregtech/api/util/virtualregistry/VirtualEntry.java b/src/main/java/gregtech/api/util/virtualregistry/VirtualEntry.java
new file mode 100644
index 00000000000..2775069f0e3
--- /dev/null
+++ b/src/main/java/gregtech/api/util/virtualregistry/VirtualEntry.java
@@ -0,0 +1,79 @@
+package gregtech.api.util.virtualregistry;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.INBTSerializable;
+
+import org.jetbrains.annotations.NotNull;
+
+public abstract class VirtualEntry implements INBTSerializable {
+
+ public static final String DEFAULT_COLOR = "FFFFFFFF";
+ protected static final String COLOR_KEY = "color";
+ protected static final String DESC_KEY = "description";
+
+ private int color = 0xFFFFFFFF;
+ private String colorStr = DEFAULT_COLOR;
+ private @NotNull String description = "";
+
+ public abstract EntryTypes extends VirtualEntry> getType();
+
+ public String getColorStr() {
+ return colorStr;
+ }
+
+ public int getColor() {
+ return this.color;
+ }
+
+ public void setColor(String color) {
+ this.color = parseColor(color);
+ this.colorStr = color.toUpperCase();
+ }
+
+ public void setColor(int color) {
+ setColor(Integer.toHexString(color));
+ }
+
+ private int parseColor(String s) {
+ // stupid java not having actual unsigned ints
+ long tmp = Long.parseLong(s, 16);
+ if (tmp > 0x7FFFFFFF) {
+ tmp -= 0x100000000L;
+ }
+ return (int) tmp;
+ }
+
+ public @NotNull String getDescription() {
+ return this.description;
+ }
+
+ public void setDescription(@NotNull String desc) {
+ this.description = desc;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof VirtualEntry other)) return false;
+ return this.getType() == other.getType() &&
+ this.color == other.color;
+ }
+
+ @Override
+ public NBTTagCompound serializeNBT() {
+ var tag = new NBTTagCompound();
+ tag.setString(COLOR_KEY, this.colorStr);
+
+ if (description != null && !description.isEmpty())
+ tag.setString(DESC_KEY, this.description);
+
+ return tag;
+ }
+
+ @Override
+ public void deserializeNBT(NBTTagCompound nbt) {
+ setColor(nbt.getString(COLOR_KEY));
+
+ if (nbt.hasKey(DESC_KEY))
+ setDescription(nbt.getString(DESC_KEY));
+ }
+}
diff --git a/src/main/java/gregtech/api/util/virtualregistry/VirtualRegistryMap.java b/src/main/java/gregtech/api/util/virtualregistry/VirtualRegistryMap.java
new file mode 100644
index 00000000000..18a2b9a81e8
--- /dev/null
+++ b/src/main/java/gregtech/api/util/virtualregistry/VirtualRegistryMap.java
@@ -0,0 +1,87 @@
+package gregtech.api.util.virtualregistry;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.INBTSerializable;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class VirtualRegistryMap implements INBTSerializable {
+
+ private final Map, Map> registryMap = new HashMap<>();
+
+ public VirtualRegistryMap(NBTTagCompound tag) {
+ deserializeNBT(tag);
+ }
+
+ public VirtualRegistryMap() {}
+
+ @SuppressWarnings("unchecked")
+ public @Nullable T getEntry(EntryTypes type, String name) {
+ if (!contains(type, name))
+ return null;
+
+ return (T) registryMap.get(type).get(name);
+ }
+
+ public void addEntry(String name, VirtualEntry entry) {
+ registryMap.computeIfAbsent(entry.getType(), k -> new HashMap<>())
+ .put(name, entry);
+ }
+
+ public boolean contains(EntryTypes> type, String name) {
+ if (!registryMap.containsKey(type))
+ return false;
+
+ return registryMap.get(type).containsKey(name);
+ }
+
+ public void deleteEntry(EntryTypes> type, String name) {
+ registryMap.get(type).remove(name);
+ }
+
+ public void clear() {
+ registryMap.clear();
+ }
+
+ public Set getEntryNames(EntryTypes> type) {
+ return registryMap.get(type).keySet();
+ }
+
+ @Override
+ public @NotNull NBTTagCompound serializeNBT() {
+ var tag = new NBTTagCompound();
+ for (var type : registryMap.keySet()) {
+ var entriesTag = new NBTTagCompound();
+ var entries = registryMap.get(type);
+ for (var name : entries.keySet()) {
+ entriesTag.setTag(name, entries.get(name).serializeNBT());
+ }
+ tag.setTag(type.toString(), entriesTag);
+ }
+ return tag;
+ }
+
+ @Override
+ public void deserializeNBT(NBTTagCompound nbt) {
+ for (var entryType : nbt.getKeySet()) {
+ EntryTypes> type;
+ if (entryType.contains(":")) {
+ type = EntryTypes.fromLocation(entryType);
+ } else {
+ type = EntryTypes.fromString(entryType);
+ }
+ if (type == null) continue;
+
+ var virtualEntries = nbt.getCompoundTag(entryType);
+ for (var name : virtualEntries.getKeySet()) {
+ var entry = virtualEntries.getCompoundTag(name);
+ addEntry(name, type.createInstance(entry));
+ }
+ }
+ }
+}
diff --git a/src/main/java/gregtech/api/util/virtualregistry/entries/VirtualTank.java b/src/main/java/gregtech/api/util/virtualregistry/entries/VirtualTank.java
new file mode 100644
index 00000000000..3ad02e5969c
--- /dev/null
+++ b/src/main/java/gregtech/api/util/virtualregistry/entries/VirtualTank.java
@@ -0,0 +1,180 @@
+package gregtech.api.util.virtualregistry.entries;
+
+import gregtech.api.util.virtualregistry.EntryTypes;
+import gregtech.api.util.virtualregistry.VirtualEntry;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.FluidTankInfo;
+import net.minecraftforge.fluids.IFluidTank;
+import net.minecraftforge.fluids.capability.IFluidHandler;
+import net.minecraftforge.fluids.capability.IFluidTankProperties;
+
+import org.jetbrains.annotations.Nullable;
+
+public class VirtualTank extends VirtualEntry implements IFluidTank, IFluidHandler {
+
+ protected static final String CAPACITY_KEY = "capacity";
+ protected static final String FLUID_KEY = "fluid";
+ private static final int DEFAULT_CAPACITY = 64000; // 64B
+
+ @Nullable
+ private FluidStack fluidStack = null;
+ private int capacity;
+ private final IFluidTankProperties[] props = new IFluidTankProperties[] {
+ createProperty(this)
+ };
+
+ public VirtualTank(int capacity) {
+ this.capacity = capacity;
+ }
+
+ public VirtualTank() {
+ this(DEFAULT_CAPACITY);
+ }
+
+ @Override
+ public EntryTypes getType() {
+ return EntryTypes.ENDER_FLUID;
+ }
+
+ @Override
+ public FluidStack getFluid() {
+ return this.fluidStack;
+ }
+
+ public void setFluid(FluidStack fluid) {
+ this.fluidStack = fluid;
+ }
+
+ @Override
+ public int getFluidAmount() {
+ return fluidStack == null ? 0 : fluidStack.amount;
+ }
+
+ @Override
+ public int getCapacity() {
+ return this.capacity;
+ }
+
+ @Override
+ public FluidTankInfo getInfo() {
+ return new FluidTankInfo(this);
+ }
+
+ @Override
+ public IFluidTankProperties[] getTankProperties() {
+ return this.props;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof VirtualTank other)) return false;
+ if (this.fluidStack == null && other.fluidStack == null)
+ return super.equals(o);
+ if (this.fluidStack == null || other.fluidStack == null)
+ return false;
+ if (this.fluidStack.isFluidStackIdentical(other.fluidStack))
+ return super.equals(o);
+
+ return false;
+ }
+
+ @Override
+ public NBTTagCompound serializeNBT() {
+ var tag = super.serializeNBT();
+ tag.setInteger(CAPACITY_KEY, this.capacity);
+
+ if (this.fluidStack != null)
+ tag.setTag(FLUID_KEY, this.fluidStack.writeToNBT(new NBTTagCompound()));
+
+ return tag;
+ }
+
+ @Override
+ public void deserializeNBT(NBTTagCompound nbt) {
+ super.deserializeNBT(nbt);
+ this.capacity = nbt.getInteger(CAPACITY_KEY);
+
+ if (nbt.hasKey(FLUID_KEY))
+ setFluid(FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag(FLUID_KEY)));
+ }
+
+ @Override
+ public int fill(FluidStack fluidStack, boolean doFill) {
+ if (fluidStack == null || fluidStack.amount <= 0 ||
+ (this.fluidStack != null && !fluidStack.isFluidEqual(this.fluidStack)))
+ return 0;
+
+ int fillAmt = Math.min(fluidStack.amount, getCapacity() - this.getFluidAmount());
+
+ if (doFill) {
+ if (this.fluidStack == null) {
+ this.fluidStack = new FluidStack(fluidStack, fillAmt);
+ } else {
+ this.fluidStack.amount += fillAmt;
+ }
+ }
+ return fillAmt;
+ }
+
+ @Nullable
+ @Override
+ public FluidStack drain(FluidStack resource, boolean doDrain) {
+ return resource == null || !resource.isFluidEqual(this.fluidStack) ? null : drain(resource.amount, doDrain);
+ }
+
+ @Nullable
+ @Override
+ public FluidStack drain(int amount, boolean doDrain) {
+ if (this.fluidStack == null || amount <= 0)
+ return null;
+
+ int drainAmt = Math.min(this.getFluidAmount(), amount);
+ FluidStack drainedFluid = new FluidStack(this.fluidStack, drainAmt);
+ if (doDrain) {
+ this.fluidStack.amount -= drainAmt;
+ if (this.fluidStack.amount <= 0) {
+ this.fluidStack = null;
+ }
+ }
+ return drainedFluid;
+ }
+
+ private static IFluidTankProperties createProperty(VirtualTank tank) {
+ return new IFluidTankProperties() {
+
+ @Nullable
+ @Override
+ public FluidStack getContents() {
+ FluidStack contents = tank.getFluid();
+ return contents == null ? null : contents.copy();
+ }
+
+ @Override
+ public int getCapacity() {
+ return tank.getCapacity();
+ }
+
+ @Override
+ public boolean canFill() {
+ return true;
+ }
+
+ @Override
+ public boolean canDrain() {
+ return true;
+ }
+
+ @Override
+ public boolean canFillFluidType(FluidStack fluidStack) {
+ return true;
+ }
+
+ @Override
+ public boolean canDrainFluidType(FluidStack fluidStack) {
+ return true;
+ }
+ };
+ }
+}
diff --git a/src/main/java/gregtech/common/EventHandlers.java b/src/main/java/gregtech/common/EventHandlers.java
index 8fa23091b99..ecbe6b16097 100644
--- a/src/main/java/gregtech/common/EventHandlers.java
+++ b/src/main/java/gregtech/common/EventHandlers.java
@@ -13,7 +13,7 @@
import gregtech.api.util.CapesRegistry;
import gregtech.api.util.GTUtility;
import gregtech.api.util.Mods;
-import gregtech.api.util.VirtualTankRegistry;
+import gregtech.api.util.virtualregistry.VirtualEnderRegistry;
import gregtech.api.worldgen.bedrockFluids.BedrockFluidVeinSaveData;
import gregtech.common.entities.EntityGTExplosive;
import gregtech.common.items.MetaItems;
@@ -327,7 +327,7 @@ public static void onPlayerTickClient(TickEvent.PlayerTickEvent event) {
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event) {
- VirtualTankRegistry.initializeStorage(event.getWorld());
+ VirtualEnderRegistry.initializeStorage(event.getWorld());
CapesRegistry.checkAdvancements(event.getWorld());
}
diff --git a/src/main/java/gregtech/common/covers/CoverBehaviors.java b/src/main/java/gregtech/common/covers/CoverBehaviors.java
index 78413327163..355fe3b0dff 100644
--- a/src/main/java/gregtech/common/covers/CoverBehaviors.java
+++ b/src/main/java/gregtech/common/covers/CoverBehaviors.java
@@ -8,6 +8,7 @@
import gregtech.api.util.GTLog;
import gregtech.client.renderer.texture.Textures;
import gregtech.common.covers.detector.*;
+import gregtech.common.covers.ender.CoverEnderFluidLink;
import gregtech.common.items.MetaItems;
import gregtech.common.items.behaviors.CoverDigitalInterfaceWirelessPlaceBehaviour;
diff --git a/src/main/java/gregtech/common/covers/CoverEnderFluidLink.java b/src/main/java/gregtech/common/covers/CoverEnderFluidLink.java
deleted file mode 100644
index a674b6fbd54..00000000000
--- a/src/main/java/gregtech/common/covers/CoverEnderFluidLink.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package gregtech.common.covers;
-
-import gregtech.api.capability.GregtechTileCapabilities;
-import gregtech.api.capability.IControllable;
-import gregtech.api.cover.CoverBase;
-import gregtech.api.cover.CoverDefinition;
-import gregtech.api.cover.CoverWithUI;
-import gregtech.api.cover.CoverableView;
-import gregtech.api.mui.GTGuiTextures;
-import gregtech.api.mui.GTGuis;
-import gregtech.api.util.FluidTankSwitchShim;
-import gregtech.api.util.GTTransferUtils;
-import gregtech.api.util.VirtualTankRegistry;
-import gregtech.client.renderer.texture.Textures;
-import gregtech.common.covers.filter.FluidFilterContainer;
-
-import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.NBTTagCompound;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.util.BlockRenderLayer;
-import net.minecraft.util.EnumActionResult;
-import net.minecraft.util.EnumFacing;
-import net.minecraft.util.EnumHand;
-import net.minecraft.util.ITickable;
-import net.minecraftforge.common.capabilities.Capability;
-import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
-import net.minecraftforge.fluids.capability.IFluidHandler;
-
-import codechicken.lib.raytracer.CuboidRayTraceResult;
-import codechicken.lib.render.CCRenderState;
-import codechicken.lib.render.pipeline.IVertexOperation;
-import codechicken.lib.vec.Cuboid6;
-import codechicken.lib.vec.Matrix4;
-import com.cleanroommc.modularui.api.drawable.IKey;
-import com.cleanroommc.modularui.drawable.DynamicDrawable;
-import com.cleanroommc.modularui.drawable.Rectangle;
-import com.cleanroommc.modularui.factory.SidedPosGuiData;
-import com.cleanroommc.modularui.screen.ModularPanel;
-import com.cleanroommc.modularui.utils.Color;
-import com.cleanroommc.modularui.value.sync.BooleanSyncValue;
-import com.cleanroommc.modularui.value.sync.EnumSyncValue;
-import com.cleanroommc.modularui.value.sync.FluidSlotSyncHandler;
-import com.cleanroommc.modularui.value.sync.PanelSyncManager;
-import com.cleanroommc.modularui.value.sync.StringSyncValue;
-import com.cleanroommc.modularui.widgets.FluidSlot;
-import com.cleanroommc.modularui.widgets.ToggleButton;
-import com.cleanroommc.modularui.widgets.layout.Column;
-import com.cleanroommc.modularui.widgets.layout.Row;
-import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.UUID;
-import java.util.regex.Pattern;
-
-public class CoverEnderFluidLink extends CoverBase implements CoverWithUI, ITickable, IControllable {
-
- public static final int TRANSFER_RATE = 8000; // mB/t
- private static final Pattern COLOR_INPUT_PATTERN = Pattern.compile("[0-9a-fA-F]*");
-
- protected CoverPump.PumpMode pumpMode = CoverPump.PumpMode.IMPORT;
- private int color = 0xFFFFFFFF;
- private UUID playerUUID = null;
- private boolean isPrivate = false;
- private boolean workingEnabled = true;
- private boolean ioEnabled = false;
- private String tempColorStr;
- private boolean isColorTemp;
- private final FluidTankSwitchShim linkedTank;
- protected final FluidFilterContainer fluidFilter;
-
- protected CoverEnderFluidLink(@NotNull CoverDefinition definition, @NotNull CoverableView coverableView,
- @NotNull EnumFacing attachedSide) {
- super(definition, coverableView, attachedSide);
- this.linkedTank = new FluidTankSwitchShim(VirtualTankRegistry.getTankCreate(makeTankName(), null));
- this.fluidFilter = new FluidFilterContainer(this);
- }
-
- private String makeTankName() {
- return "EFLink#" + Integer.toHexString(this.color).toUpperCase();
- }
-
- private UUID getTankUUID() {
- return isPrivate ? playerUUID : null;
- }
-
- public FluidFilterContainer getFluidFilterContainer() {
- return this.fluidFilter;
- }
-
- public boolean isIOEnabled() {
- return this.ioEnabled;
- }
-
- @Override
- public boolean canAttach(@NotNull CoverableView coverable, @NotNull EnumFacing side) {
- return coverable.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side);
- }
-
- @Override
- public void renderCover(@NotNull CCRenderState renderState, @NotNull Matrix4 translation,
- IVertexOperation[] pipeline, @NotNull Cuboid6 plateBox, @NotNull BlockRenderLayer layer) {
- Textures.ENDER_FLUID_LINK.renderSided(getAttachedSide(), plateBox, renderState, pipeline, translation);
- }
-
- @Override
- public @NotNull EnumActionResult onScrewdriverClick(@NotNull EntityPlayer playerIn, @NotNull EnumHand hand,
- @NotNull CuboidRayTraceResult hitResult) {
- if (!getWorld().isRemote) {
- openUI((EntityPlayerMP) playerIn);
- }
- return EnumActionResult.SUCCESS;
- }
-
- @Override
- public void onAttachment(@NotNull CoverableView coverableView, @NotNull EnumFacing side,
- @Nullable EntityPlayer player, @NotNull ItemStack itemStack) {
- super.onAttachment(coverableView, side, player, itemStack);
- if (player != null) {
- this.playerUUID = player.getUniqueID();
- }
- }
-
- @Override
- public void onRemoval() {
- dropInventoryContents(fluidFilter);
- }
-
- @Override
- public void update() {
- if (workingEnabled && ioEnabled) {
- transferFluids();
- }
- }
-
- protected void transferFluids() {
- IFluidHandler fluidHandler = getCoverableView().getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
- getAttachedSide());
- if (fluidHandler == null) return;
- if (pumpMode == CoverPump.PumpMode.IMPORT) {
- GTTransferUtils.transferFluids(fluidHandler, linkedTank, TRANSFER_RATE, fluidFilter::test);
- } else if (pumpMode == CoverPump.PumpMode.EXPORT) {
- GTTransferUtils.transferFluids(linkedTank, fluidHandler, TRANSFER_RATE, fluidFilter::test);
- }
- }
-
- public void setPumpMode(CoverPump.PumpMode pumpMode) {
- this.pumpMode = pumpMode;
- markDirty();
- }
-
- public CoverPump.PumpMode getPumpMode() {
- return pumpMode;
- }
-
- @Override
- public void openUI(EntityPlayerMP player) {
- CoverWithUI.super.openUI(player);
- isColorTemp = false;
- }
-
- @Override
- public boolean usesMui2() {
- return true;
- }
-
- @Override
- public ModularPanel buildUI(SidedPosGuiData guiData, PanelSyncManager guiSyncManager) {
- var panel = GTGuis.createPanel(this, 176, 192);
-
- getFluidFilterContainer().setMaxTransferSize(1);
-
- return panel.child(CoverWithUI.createTitleRow(getPickItem()))
- .child(createWidgets(panel, guiSyncManager))
- .bindPlayerInventory();
- }
-
- protected Column createWidgets(ModularPanel panel, PanelSyncManager syncManager) {
- var isPrivate = new BooleanSyncValue(this::isPrivate, this::setPrivate);
- isPrivate.updateCacheFromSource(true);
-
- var color = new StringSyncValue(this::getColorStr, this::updateColor);
- color.updateCacheFromSource(true);
-
- var pumpMode = new EnumSyncValue<>(CoverPump.PumpMode.class, this::getPumpMode, this::setPumpMode);
- syncManager.syncValue("pump_mode", pumpMode);
- pumpMode.updateCacheFromSource(true);
-
- var ioEnabled = new BooleanSyncValue(this::isIOEnabled, this::setIoEnabled);
-
- var fluidTank = new FluidSlotSyncHandler(this.linkedTank);
- fluidTank.updateCacheFromSource(true);
-
- return new Column().coverChildrenHeight().top(24)
- .margin(7, 0).widthRel(1f)
- .child(new Row().marginBottom(2)
- .coverChildrenHeight()
- .child(new ToggleButton()
- .tooltip(tooltip -> tooltip.setAutoUpdate(true))
- .background(GTGuiTextures.PRIVATE_MODE_BUTTON[0])
- .hoverBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[0])
- .selectedBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[1])
- .selectedHoverBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[1])
- .tooltipBuilder(tooltip -> tooltip.addLine(IKey.lang(this.isPrivate ?
- "cover.ender_fluid_link.private.tooltip.enabled" :
- "cover.ender_fluid_link.private.tooltip.disabled")))
- .marginRight(2)
- .value(isPrivate))
- .child(new DynamicDrawable(() -> new Rectangle()
- .setColor(this.color)
- .asIcon().size(16))
- .asWidget()
- .background(GTGuiTextures.SLOT)
- .size(18).marginRight(2))
- .child(new TextFieldWidget().height(18)
- .value(color)
- .setValidator(s -> {
- if (s.length() != 8) {
- return color.getStringValue();
- }
- return s;
- })
- .setPattern(COLOR_INPUT_PATTERN)
- .widthRel(0.5f).marginRight(2))
- .child(new FluidSlot().size(18)
- .syncHandler(fluidTank)))
- .child(new Row().marginBottom(2)
- .coverChildrenHeight()
- .child(new ToggleButton()
- .value(ioEnabled)
- .overlay(IKey.dynamic(() -> IKey.lang(this.ioEnabled ?
- "behaviour.soft_hammer.enabled" :
- "behaviour.soft_hammer.disabled").get())
- .color(Color.WHITE.darker(1)))
- .widthRel(0.6f)
- .left(0)))
- .child(getFluidFilterContainer().initUI(panel, syncManager))
- .child(new EnumRowBuilder<>(CoverPump.PumpMode.class)
- .value(pumpMode)
- .overlay(GTGuiTextures.CONVEYOR_MODE_OVERLAY)
- .lang("cover.pump.mode")
- .build());
- }
-
- public void updateColor(String str) {
- if (str.length() == 8) {
- isColorTemp = false;
- // stupid java not having actual unsigned ints
- long tmp = Long.parseLong(str, 16);
- if (tmp > 0x7FFFFFFF) {
- tmp -= 0x100000000L;
- }
- this.color = (int) tmp;
- updateTankLink();
- } else {
- tempColorStr = str;
- isColorTemp = true;
- }
- }
-
- public String getColorStr() {
- return isColorTemp ? tempColorStr : Integer.toHexString(this.color).toUpperCase();
- }
-
- public void updateTankLink() {
- this.linkedTank.changeTank(VirtualTankRegistry.getTankCreate(makeTankName(), getTankUUID()));
- markDirty();
- }
-
- @Override
- public void writeToNBT(NBTTagCompound tagCompound) {
- super.writeToNBT(tagCompound);
- tagCompound.setInteger("Frequency", color);
- tagCompound.setInteger("PumpMode", pumpMode.ordinal());
- tagCompound.setBoolean("WorkingAllowed", workingEnabled);
- tagCompound.setBoolean("IOAllowed", ioEnabled);
- tagCompound.setBoolean("Private", isPrivate);
- tagCompound.setString("PlacedUUID", playerUUID.toString());
- tagCompound.setTag("Filter", fluidFilter.serializeNBT());
- }
-
- @Override
- public void readFromNBT(NBTTagCompound tagCompound) {
- super.readFromNBT(tagCompound);
- this.color = tagCompound.getInteger("Frequency");
- this.pumpMode = CoverPump.PumpMode.values()[tagCompound.getInteger("PumpMode")];
- this.workingEnabled = tagCompound.getBoolean("WorkingAllowed");
- this.ioEnabled = tagCompound.getBoolean("IOAllowed");
- this.isPrivate = tagCompound.getBoolean("Private");
- this.playerUUID = UUID.fromString(tagCompound.getString("PlacedUUID"));
- this.fluidFilter.deserializeNBT(tagCompound.getCompoundTag("Filter"));
- updateTankLink();
- }
-
- @Override
- public void writeInitialSyncData(PacketBuffer packetBuffer) {
- packetBuffer.writeInt(this.color);
- packetBuffer.writeString(this.playerUUID == null ? "null" : this.playerUUID.toString());
- }
-
- @Override
- public void readInitialSyncData(PacketBuffer packetBuffer) {
- this.color = packetBuffer.readInt();
- // does client even need uuid info? just in case
- String uuidStr = packetBuffer.readString(36);
- this.playerUUID = uuidStr.equals("null") ? null : UUID.fromString(uuidStr);
- // client does not need the actual tank reference, the default one will do just fine
- }
-
- @Override
- public boolean isWorkingEnabled() {
- return workingEnabled;
- }
-
- @Override
- public void setWorkingEnabled(boolean isActivationAllowed) {
- this.workingEnabled = isActivationAllowed;
- }
-
- public T getCapability(Capability capability, T defaultValue) {
- if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
- return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(linkedTank);
- }
- if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) {
- return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this);
- }
- return defaultValue;
- }
-
- private boolean isIoEnabled() {
- return ioEnabled;
- }
-
- private void setIoEnabled(boolean ioEnabled) {
- this.ioEnabled = ioEnabled;
- }
-
- private boolean isPrivate() {
- return isPrivate;
- }
-
- private void setPrivate(boolean isPrivate) {
- this.isPrivate = isPrivate;
- updateTankLink();
- }
-}
diff --git a/src/main/java/gregtech/common/covers/ender/CoverAbstractEnderLink.java b/src/main/java/gregtech/common/covers/ender/CoverAbstractEnderLink.java
new file mode 100644
index 00000000000..eb5c6a81d9d
--- /dev/null
+++ b/src/main/java/gregtech/common/covers/ender/CoverAbstractEnderLink.java
@@ -0,0 +1,513 @@
+package gregtech.common.covers.ender;
+
+import gregtech.api.capability.GregtechDataCodes;
+import gregtech.api.capability.IControllable;
+import gregtech.api.cover.CoverBase;
+import gregtech.api.cover.CoverDefinition;
+import gregtech.api.cover.CoverWithUI;
+import gregtech.api.cover.CoverableView;
+import gregtech.api.mui.GTGuiTextures;
+import gregtech.api.mui.GTGuis;
+import gregtech.api.util.virtualregistry.EntryTypes;
+import gregtech.api.util.virtualregistry.VirtualEnderRegistry;
+import gregtech.api.util.virtualregistry.VirtualEntry;
+import gregtech.common.mui.widget.InteractableText;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.util.EnumActionResult;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.EnumHand;
+import net.minecraft.util.ITickable;
+
+import codechicken.lib.raytracer.CuboidRayTraceResult;
+import com.cleanroommc.modularui.api.drawable.IKey;
+import com.cleanroommc.modularui.api.widget.IWidget;
+import com.cleanroommc.modularui.api.widget.Interactable;
+import com.cleanroommc.modularui.drawable.DynamicDrawable;
+import com.cleanroommc.modularui.drawable.GuiTextures;
+import com.cleanroommc.modularui.drawable.Rectangle;
+import com.cleanroommc.modularui.factory.SidedPosGuiData;
+import com.cleanroommc.modularui.network.NetworkUtils;
+import com.cleanroommc.modularui.screen.ModularPanel;
+import com.cleanroommc.modularui.utils.Color;
+import com.cleanroommc.modularui.value.sync.BooleanSyncValue;
+import com.cleanroommc.modularui.value.sync.PanelSyncHandler;
+import com.cleanroommc.modularui.value.sync.PanelSyncManager;
+import com.cleanroommc.modularui.value.sync.StringSyncValue;
+import com.cleanroommc.modularui.widgets.ButtonWidget;
+import com.cleanroommc.modularui.widgets.ListWidget;
+import com.cleanroommc.modularui.widgets.ToggleButton;
+import com.cleanroommc.modularui.widgets.layout.Column;
+import com.cleanroommc.modularui.widgets.layout.Row;
+import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+@SuppressWarnings("SameParameterValue")
+public abstract class CoverAbstractEnderLink extends CoverBase
+ implements CoverWithUI, ITickable, IControllable {
+
+ protected static final Pattern COLOR_INPUT_PATTERN = Pattern.compile("[0-9a-fA-F]*");
+ public static final int UPDATE_PRIVATE = GregtechDataCodes.assignId();
+
+ protected T activeEntry = null;
+ protected String color = VirtualEntry.DEFAULT_COLOR;
+ protected UUID playerUUID = null;
+ private boolean isPrivate = false;
+ private boolean workingEnabled = true;
+ private boolean ioEnabled = false;
+
+ public CoverAbstractEnderLink(@NotNull CoverDefinition definition, @NotNull CoverableView coverableView,
+ @NotNull EnumFacing attachedSide) {
+ super(definition, coverableView, attachedSide);
+ updateLink();
+ }
+
+ protected void updateLink() {
+ this.activeEntry = VirtualEnderRegistry.getOrCreateEntry(getOwner(), getType(), createName());
+ this.activeEntry.setColor(this.color);
+ markDirty();
+ }
+
+ protected abstract EntryTypes getType();
+
+ public String getColorStr() {
+ return this.color;
+ }
+
+ protected final String createName() {
+ return identifier() + this.color;
+ }
+
+ protected abstract String identifier();
+
+ protected final UUID getOwner() {
+ return isPrivate ? playerUUID : null;
+ }
+
+ @Override
+ public void readCustomData(int discriminator, @NotNull PacketBuffer buf) {
+ super.readCustomData(discriminator, buf);
+ if (discriminator == UPDATE_PRIVATE) {
+ setPrivate(buf.readBoolean());
+ updateLink();
+ }
+ }
+
+ @Override
+ public @NotNull EnumActionResult onScrewdriverClick(@NotNull EntityPlayer playerIn, @NotNull EnumHand hand,
+ @NotNull CuboidRayTraceResult hitResult) {
+ if (!getWorld().isRemote) {
+ openUI((EntityPlayerMP) playerIn);
+ }
+ return EnumActionResult.SUCCESS;
+ }
+
+ @Override
+ public void onAttachment(@NotNull CoverableView coverableView, @NotNull EnumFacing side,
+ @Nullable EntityPlayer player, @NotNull ItemStack itemStack) {
+ super.onAttachment(coverableView, side, player, itemStack);
+ if (player != null) {
+ this.playerUUID = player.getUniqueID();
+ }
+ }
+
+ public void updateColor(String str) {
+ if (str.length() == 8) {
+ this.color = str.toUpperCase();
+ updateLink();
+ }
+ }
+
+ @Override
+ public boolean usesMui2() {
+ return true;
+ }
+
+ @Override
+ public ModularPanel buildUI(SidedPosGuiData guiData, PanelSyncManager guiSyncManager) {
+ var panel = GTGuis.createPanel(this, 176, 192);
+
+ return panel.child(CoverWithUI.createTitleRow(getPickItem()))
+ .child(createWidgets(panel, guiSyncManager))
+ .bindPlayerInventory();
+ }
+
+ protected Column createWidgets(ModularPanel panel, PanelSyncManager syncManager) {
+ var name = new StringSyncValue(this::getColorStr, this::updateColor);
+
+ var entrySelectorSH = createEntrySelector(panel);
+ syncManager.syncValue("entry_selector", entrySelectorSH);
+
+ return new Column().coverChildrenHeight().top(24)
+ .margin(7, 0).widthRel(1f)
+ .child(new Row().marginBottom(2)
+ .coverChildrenHeight()
+ .child(createPrivateButton())
+ .child(createColorIcon())
+ .child(new TextFieldWidget()
+ .height(18)
+ .value(name)
+ .setPattern(COLOR_INPUT_PATTERN)
+ .widthRel(0.5f)
+ .marginRight(2))
+ .child(createEntrySlot())
+ .child(new ButtonWidget<>()
+ .overlay(GTGuiTextures.MENU_OVERLAY)
+ .background(GTGuiTextures.MC_BUTTON)
+ .disableHoverBackground()
+ .addTooltipLine(IKey.lang("cover.generic.ender.open_selector"))
+ .onMousePressed(i -> {
+ if (entrySelectorSH.isPanelOpen()) {
+ entrySelectorSH.closePanel();
+ } else {
+ entrySelectorSH.openPanel();
+ }
+ Interactable.playButtonClickSound();
+ return true;
+ })))
+ .child(createIoRow());
+ }
+
+ protected abstract PanelSyncHandler createEntrySelector(ModularPanel panel);
+
+ protected abstract IWidget createEntrySlot();
+
+ protected IWidget createColorIcon() {
+ // todo color selector popup panel
+ return new DynamicDrawable(() -> new Rectangle()
+ .setColor(this.activeEntry.getColor())
+ .asIcon().size(16))
+ .asWidget()
+ .background(GTGuiTextures.SLOT)
+ .size(18)
+ .marginRight(2);
+ }
+
+ protected IWidget createPrivateButton() {
+ var isPrivate = new BooleanSyncValue(this::isPrivate, this::setPrivate);
+ isPrivate.updateCacheFromSource(true);
+
+ return new ToggleButton()
+ .tooltip(tooltip -> tooltip.setAutoUpdate(true))
+ .background(GTGuiTextures.PRIVATE_MODE_BUTTON[0])
+ .hoverBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[0])
+ .selectedBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[1])
+ .selectedHoverBackground(GTGuiTextures.PRIVATE_MODE_BUTTON[1])
+ .tooltipBuilder(tooltip -> tooltip.addLine(IKey.lang(this.isPrivate ?
+ "cover.ender_fluid_link.private.tooltip.enabled" :
+ "cover.ender_fluid_link.private.tooltip.disabled")))
+ .marginRight(2)
+ .value(isPrivate);
+ }
+
+ protected IWidget createIoRow() {
+ var ioEnabled = new BooleanSyncValue(this::isIoEnabled, this::setIoEnabled);
+
+ return new Row().marginBottom(2)
+ .coverChildrenHeight()
+ .child(new ToggleButton()
+ .value(ioEnabled)
+ .overlay(IKey.dynamic(() -> IKey.lang(this.ioEnabled ?
+ "behaviour.soft_hammer.enabled" :
+ "behaviour.soft_hammer.disabled").get())
+ .color(Color.WHITE.darker(1)))
+ .widthRel(0.6f)
+ .left(0));
+ }
+
+ @Override
+ public boolean isWorkingEnabled() {
+ return workingEnabled;
+ }
+
+ @Override
+ public void setWorkingEnabled(boolean isActivationAllowed) {
+ this.workingEnabled = isActivationAllowed;
+ }
+
+ public boolean isIoEnabled() {
+ return ioEnabled;
+ }
+
+ protected void setIoEnabled(boolean ioEnabled) {
+ this.ioEnabled = ioEnabled;
+ }
+
+ private boolean isPrivate() {
+ return isPrivate;
+ }
+
+ private void setPrivate(boolean isPrivate) {
+ this.isPrivate = isPrivate;
+ updateLink();
+ writeCustomData(UPDATE_PRIVATE, buffer -> buffer.writeBoolean(this.isPrivate));
+ }
+
+ @Override
+ public void writeInitialSyncData(PacketBuffer packetBuffer) {
+ packetBuffer.writeString(this.playerUUID == null ? "null" : this.playerUUID.toString());
+ }
+
+ @Override
+ public void readInitialSyncData(PacketBuffer packetBuffer) {
+ // does client even need uuid info? just in case
+ String uuidStr = packetBuffer.readString(36);
+ this.playerUUID = uuidStr.equals("null") ? null : UUID.fromString(uuidStr);
+ }
+
+ @Override
+ public void readFromNBT(@NotNull NBTTagCompound nbt) {
+ super.readFromNBT(nbt);
+ this.ioEnabled = nbt.getBoolean("IOAllowed");
+ this.isPrivate = nbt.getBoolean("Private");
+ this.workingEnabled = nbt.getBoolean("WorkingAllowed");
+ this.playerUUID = UUID.fromString(nbt.getString("PlacedUUID"));
+ int color = nbt.getInteger("Frequency");
+ this.color = Integer.toHexString(color).toUpperCase();
+ updateLink();
+ }
+
+ @Override
+ public void writeToNBT(@NotNull NBTTagCompound nbt) {
+ super.writeToNBT(nbt);
+ nbt.setBoolean("IOAllowed", ioEnabled);
+ nbt.setBoolean("Private", isPrivate);
+ nbt.setBoolean("WorkingAllowed", workingEnabled);
+ nbt.setString("PlacedUUID", playerUUID.toString());
+ nbt.setInteger("Frequency", activeEntry.getColor());
+ }
+
+ protected abstract class EntrySelectorSH extends PanelSyncHandler {
+
+ private static final int TRACK_SUBPANELS = 3;
+ private static final int DELETE_ENTRY = 1;
+ private final EntryTypes type;
+ private final ModularPanel mainPanel;
+ private static final String PANEL_NAME = "entry_selector";
+ private final Set opened = new HashSet<>();
+ protected UUID playerUUID;
+
+ protected EntrySelectorSH(ModularPanel mainPanel, EntryTypes type) {
+ super(mainPanel, EntrySelectorSH::defaultPanel);
+ this.type = type;
+ this.mainPanel = mainPanel;
+ }
+
+ @Override
+ public void init(String key, PanelSyncManager syncManager) {
+ super.init(key, syncManager);
+ this.playerUUID = syncManager.getPlayer().getUniqueID();
+ }
+
+ private static ModularPanel defaultPanel(PanelSyncManager syncManager, PanelSyncHandler syncHandler) {
+ return GTGuis.createPopupPanel(PANEL_NAME, 168, 112);
+ }
+
+ public UUID getPlayerUUID() {
+ return isPrivate ? playerUUID : null;
+ }
+
+ @Override
+ public ModularPanel createUI(PanelSyncManager syncManager) {
+ List names = new ArrayList<>(VirtualEnderRegistry.getEntryNames(getPlayerUUID(), type));
+ return super.createUI(syncManager)
+ .child(IKey.lang("cover.generic.ender.known_channels")
+ .color(UI_TITLE_COLOR).asWidget()
+ .top(6)
+ .left(4))
+ .child(ListWidget.builder(names, name -> createRow(name, this.mainPanel, syncManager))
+ .background(GTGuiTextures.DISPLAY.asIcon()
+ .width(168 - 8)
+ .height(112 - 20))
+ .paddingTop(1)
+ .size(168 - 12, 112 - 24)
+ .left(4)
+ .bottom(6));
+ }
+
+ protected IWidget createRow(String name, ModularPanel mainPanel, PanelSyncManager syncManager) {
+ T entry = VirtualEnderRegistry.getEntry(getPlayerUUID(), this.type, name);
+ String key = String.format("entry#%s_description", entry.getColorStr());
+ var entryDescriptionSH = new EntryDescriptionSH(mainPanel, key, entry);
+ syncManager.syncValue(key, isPrivate ? 1 : 0, entryDescriptionSH);
+
+ return new Row()
+ .left(4)
+ .marginBottom(2)
+ .height(18)
+ .widthRel(0.98f)
+ .setEnabledIf(row -> VirtualEnderRegistry.hasEntry(getOwner(), this.type, name))
+ .child(new Rectangle()
+ .setColor(entry.getColor())
+ .asWidget()
+ .marginRight(4)
+ .size(16)
+ .background(GTGuiTextures.SLOT.asIcon().size(18))
+ .top(1))
+ .child(new InteractableText<>(entry, CoverAbstractEnderLink.this::updateColor)
+ .tooltip(tooltip -> tooltip.setAutoUpdate(true))
+ .tooltipBuilder(tooltip -> {
+ String desc = entry.getDescription();
+ if (!desc.isEmpty())
+ tooltip.addLine(desc);
+ })
+ .width(64)
+ .height(16)
+ .top(1)
+ .marginRight(4))
+ .child(new ButtonWidget<>()
+ .overlay(GuiTextures.GEAR)
+ .addTooltipLine(IKey.lang("cover.generic.ender.set_description.tooltip"))
+ .onMousePressed(i -> {
+ // open entry settings
+ if (entryDescriptionSH.isPanelOpen()) {
+ entryDescriptionSH.closePanel();
+ } else {
+ entryDescriptionSH.openPanel();
+ }
+ Interactable.playButtonClickSound();
+ return true;
+ }))
+ .child(createSlotWidget(entry))
+ .child(new ButtonWidget<>()
+ .overlay(GTGuiTextures.BUTTON_CROSS)
+ .setEnabledIf(w -> !Objects.equals(entry.getColor(), activeEntry.getColor()))
+ .addTooltipLine(IKey.lang("cover.generic.ender.delete_entry"))
+ .onMousePressed(i -> {
+ // todo option to force delete, maybe as a popup?
+ deleteEntry(getPlayerUUID(), name);
+ syncToServer(1, buffer -> {
+ NetworkUtils.writeStringSafe(buffer, getPlayerUUID().toString());
+ NetworkUtils.writeStringSafe(buffer, name);
+ });
+ Interactable.playButtonClickSound();
+ return true;
+ }));
+ }
+
+ @Override
+ public void closePanel() {
+ var manager = getSyncManager().getModularSyncManager().getPanelSyncManager(PANEL_NAME);
+ for (var key : opened) {
+ if (manager.getSyncHandler(key) instanceof PanelSyncHandler psh) {
+ psh.closePanel();
+ }
+ }
+ super.closePanel();
+ }
+
+ @Override
+ @SuppressWarnings("UnstableApiUsage")
+ public void closePanelInternal() {
+ var manager = getSyncManager().getModularSyncManager().getPanelSyncManager(PANEL_NAME);
+ for (var key : opened) {
+ if (manager.getSyncHandler(key) instanceof PanelSyncHandler psh) {
+ psh.closePanel();
+ }
+ }
+ super.closePanelInternal();
+ }
+
+ @Override
+ public void readOnClient(int i, PacketBuffer packetBuffer) throws IOException {
+ if (i == TRACK_SUBPANELS) {
+ handleTracking(packetBuffer);
+ }
+ super.readOnClient(i, packetBuffer);
+ }
+
+ @Override
+ public void readOnServer(int i, PacketBuffer packetBuffer) throws IOException {
+ if (i == TRACK_SUBPANELS) {
+ handleTracking(packetBuffer);
+ }
+ super.readOnServer(i, packetBuffer);
+ if (i == DELETE_ENTRY) {
+ UUID uuid = UUID.fromString(NetworkUtils.readStringSafe(packetBuffer));
+ String name = NetworkUtils.readStringSafe(packetBuffer);
+ deleteEntry(uuid, name);
+ }
+ }
+
+ private void handleTracking(PacketBuffer buffer) {
+ boolean add = buffer.readBoolean();
+ String key = NetworkUtils.readStringSafe(buffer);
+ if (key != null) {
+ if (add) opened.add(key);
+ else opened.remove(key);
+ }
+ }
+
+ private class EntryDescriptionSH extends PanelSyncHandler {
+
+ /**
+ * Creates a PanelSyncHandler
+ *
+ * @param mainPanel the main panel of the current GUI
+ */
+ public EntryDescriptionSH(ModularPanel mainPanel, String key, VirtualEntry entry) {
+ super(mainPanel, (syncManager, syncHandler) -> defaultPanel(syncHandler, key, entry));
+ }
+
+ private static ModularPanel defaultPanel(@NotNull PanelSyncHandler syncHandler, String key,
+ VirtualEntry entry) {
+ return GTGuis.createPopupPanel(key, 168, 36 + 6)
+ .child(IKey.lang("cover.generic.ender.set_description.title", entry.getColorStr())
+ .color(UI_TITLE_COLOR)
+ .asWidget()
+ .left(4)
+ .top(6))
+ .child(new TextFieldWidget()
+ .setTextColor(Color.WHITE.darker(1))
+ .widthRel(0.95f)
+ .height(18)
+ .value(new StringSyncValue(entry::getDescription, string -> {
+ entry.setDescription(string);
+ if (syncHandler.isPanelOpen()) {
+ syncHandler.closePanel();
+ }
+ }))
+ .alignX(0.5f)
+ .bottom(6));
+ }
+
+ @Override
+ public void openPanel() {
+ opened.add(getKey());
+ EntrySelectorSH.this.sync(3, buffer -> {
+ buffer.writeBoolean(true);
+ NetworkUtils.writeStringSafe(buffer, getKey());
+ });
+ super.openPanel();
+ }
+
+ @Override
+ public void closePanel() {
+ opened.remove(getKey());
+ EntrySelectorSH.this.sync(3, buffer -> {
+ buffer.writeBoolean(false);
+ NetworkUtils.writeStringSafe(buffer, getKey());
+ });
+ super.closePanel();
+ }
+ }
+
+ protected abstract IWidget createSlotWidget(T entry);
+
+ protected abstract void deleteEntry(UUID player, String name);
+ }
+}
diff --git a/src/main/java/gregtech/common/covers/ender/CoverEnderFluidLink.java b/src/main/java/gregtech/common/covers/ender/CoverEnderFluidLink.java
new file mode 100644
index 00000000000..27c338154b1
--- /dev/null
+++ b/src/main/java/gregtech/common/covers/ender/CoverEnderFluidLink.java
@@ -0,0 +1,193 @@
+package gregtech.common.covers.ender;
+
+import gregtech.api.capability.GregtechTileCapabilities;
+import gregtech.api.capability.IControllable;
+import gregtech.api.cover.CoverDefinition;
+import gregtech.api.cover.CoverWithUI;
+import gregtech.api.cover.CoverableView;
+import gregtech.api.mui.GTGuiTextures;
+import gregtech.api.util.FluidTankSwitchShim;
+import gregtech.api.util.GTTransferUtils;
+import gregtech.api.util.virtualregistry.EntryTypes;
+import gregtech.api.util.virtualregistry.VirtualEnderRegistry;
+import gregtech.api.util.virtualregistry.entries.VirtualTank;
+import gregtech.client.renderer.texture.Textures;
+import gregtech.common.covers.CoverPump;
+import gregtech.common.covers.filter.FluidFilterContainer;
+import gregtech.common.mui.widget.GTFluidSlot;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockRenderLayer;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.ITickable;
+import net.minecraftforge.common.capabilities.Capability;
+import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
+import net.minecraftforge.fluids.capability.IFluidHandler;
+
+import codechicken.lib.render.CCRenderState;
+import codechicken.lib.render.pipeline.IVertexOperation;
+import codechicken.lib.vec.Cuboid6;
+import codechicken.lib.vec.Matrix4;
+import com.cleanroommc.modularui.api.widget.IWidget;
+import com.cleanroommc.modularui.screen.ModularPanel;
+import com.cleanroommc.modularui.value.sync.EnumSyncValue;
+import com.cleanroommc.modularui.value.sync.PanelSyncHandler;
+import com.cleanroommc.modularui.value.sync.PanelSyncManager;
+import com.cleanroommc.modularui.widgets.layout.Column;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class CoverEnderFluidLink extends CoverAbstractEnderLink
+ implements CoverWithUI, ITickable, IControllable {
+
+ public static final int TRANSFER_RATE = 8000; // mB/t
+
+ protected CoverPump.PumpMode pumpMode = CoverPump.PumpMode.IMPORT;
+ private final FluidTankSwitchShim linkedTank;
+ protected final FluidFilterContainer fluidFilter;
+
+ public CoverEnderFluidLink(@NotNull CoverDefinition definition, @NotNull CoverableView coverableView,
+ @NotNull EnumFacing attachedSide) {
+ super(definition, coverableView, attachedSide);
+ this.linkedTank = new FluidTankSwitchShim(this.activeEntry);
+ this.fluidFilter = new FluidFilterContainer(this);
+ }
+
+ @Override
+ protected void updateLink() {
+ super.updateLink();
+ if (this.linkedTank != null)
+ this.linkedTank.changeTank(this.activeEntry);
+ }
+
+ @Override
+ protected EntryTypes getType() {
+ return EntryTypes.ENDER_FLUID;
+ }
+
+ @Override
+ protected String identifier() {
+ return "EFLink#";
+ }
+
+ public FluidFilterContainer getFluidFilterContainer() {
+ return this.fluidFilter;
+ }
+
+ @Override
+ public boolean canAttach(@NotNull CoverableView coverable, @NotNull EnumFacing side) {
+ return coverable.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side);
+ }
+
+ @Override
+ public void renderCover(@NotNull CCRenderState renderState, @NotNull Matrix4 translation,
+ IVertexOperation[] pipeline, @NotNull Cuboid6 plateBox, @NotNull BlockRenderLayer layer) {
+ Textures.ENDER_FLUID_LINK.renderSided(getAttachedSide(), plateBox, renderState, pipeline, translation);
+ }
+
+ @Override
+ public void onRemoval() {
+ dropInventoryContents(fluidFilter);
+ }
+
+ @Override
+ public void update() {
+ if (isWorkingEnabled() && isIoEnabled()) {
+ transferFluids();
+ }
+ }
+
+ protected void transferFluids() {
+ IFluidHandler fluidHandler = getCoverableView().getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
+ getAttachedSide());
+ if (fluidHandler == null) return;
+ if (pumpMode == CoverPump.PumpMode.IMPORT) {
+ GTTransferUtils.transferFluids(fluidHandler, activeEntry, TRANSFER_RATE, fluidFilter::test);
+ } else if (pumpMode == CoverPump.PumpMode.EXPORT) {
+ GTTransferUtils.transferFluids(activeEntry, fluidHandler, TRANSFER_RATE, fluidFilter::test);
+ }
+ }
+
+ public void setPumpMode(CoverPump.PumpMode pumpMode) {
+ this.pumpMode = pumpMode;
+ markDirty();
+ }
+
+ public CoverPump.PumpMode getPumpMode() {
+ return pumpMode;
+ }
+
+ @Override
+ protected PanelSyncHandler createEntrySelector(ModularPanel panel) {
+ return new EntrySelectorSH(panel, EntryTypes.ENDER_FLUID) {
+
+ @Override
+ protected IWidget createSlotWidget(VirtualTank entry) {
+ var fluidTank = GTFluidSlot.sync(entry)
+ .canFillSlot(false)
+ .canDrainSlot(false);
+
+ return new GTFluidSlot()
+ .size(18)
+ .background(GTGuiTextures.FLUID_SLOT)
+ .syncHandler(fluidTank)
+ .marginRight(2);
+ }
+
+ @Override
+ protected void deleteEntry(UUID uuid, String name) {
+ VirtualEnderRegistry.deleteEntry(uuid, getType(), name, tank -> tank.getFluidAmount() == 0);
+ }
+ };
+ }
+
+ @Override
+ protected IWidget createEntrySlot() {
+ return new GTFluidSlot()
+ .size(18)
+ .background(GTGuiTextures.FLUID_SLOT)
+ .syncHandler(this.linkedTank)
+ .marginRight(2);
+ }
+
+ protected Column createWidgets(ModularPanel panel, PanelSyncManager syncManager) {
+ getFluidFilterContainer().setMaxTransferSize(1);
+
+ var pumpMode = new EnumSyncValue<>(CoverPump.PumpMode.class, this::getPumpMode, this::setPumpMode);
+ syncManager.syncValue("pump_mode", pumpMode);
+ pumpMode.updateCacheFromSource(true);
+
+ return super.createWidgets(panel, syncManager)
+ .child(getFluidFilterContainer().initUI(panel, syncManager))
+ .child(new EnumRowBuilder<>(CoverPump.PumpMode.class)
+ .value(pumpMode)
+ .overlay(GTGuiTextures.CONVEYOR_MODE_OVERLAY)
+ .lang("cover.pump.mode")
+ .build());
+ }
+
+ @Override
+ public void writeToNBT(NBTTagCompound tagCompound) {
+ super.writeToNBT(tagCompound);
+ tagCompound.setInteger("PumpMode", pumpMode.ordinal());
+ tagCompound.setTag("Filter", fluidFilter.serializeNBT());
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound tagCompound) {
+ super.readFromNBT(tagCompound);
+ this.pumpMode = CoverPump.PumpMode.values()[tagCompound.getInteger("PumpMode")];
+ this.fluidFilter.deserializeNBT(tagCompound.getCompoundTag("Filter"));
+ }
+
+ public T getCapability(Capability capability, T defaultValue) {
+ if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
+ return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(this.activeEntry);
+ }
+ if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) {
+ return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this);
+ }
+ return defaultValue;
+ }
+}
diff --git a/src/main/java/gregtech/common/mui/widget/GTFluidSlot.java b/src/main/java/gregtech/common/mui/widget/GTFluidSlot.java
new file mode 100644
index 00000000000..1b0ccff4ebe
--- /dev/null
+++ b/src/main/java/gregtech/common/mui/widget/GTFluidSlot.java
@@ -0,0 +1,142 @@
+package gregtech.common.mui.widget;
+
+import gregtech.api.GTValues;
+import gregtech.api.mui.sync.GTFluidSyncHandler;
+import gregtech.api.util.FluidTooltipUtil;
+import gregtech.api.util.LocalizationUtils;
+import gregtech.client.utils.TooltipHelper;
+
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.fluids.IFluidTank;
+
+import com.cleanroommc.modularui.api.ITheme;
+import com.cleanroommc.modularui.api.drawable.IKey;
+import com.cleanroommc.modularui.api.widget.Interactable;
+import com.cleanroommc.modularui.drawable.GuiDraw;
+import com.cleanroommc.modularui.drawable.TextRenderer;
+import com.cleanroommc.modularui.integration.jei.JeiIngredientProvider;
+import com.cleanroommc.modularui.screen.Tooltip;
+import com.cleanroommc.modularui.screen.viewport.GuiContext;
+import com.cleanroommc.modularui.theme.WidgetSlotTheme;
+import com.cleanroommc.modularui.theme.WidgetTheme;
+import com.cleanroommc.modularui.utils.Alignment;
+import com.cleanroommc.modularui.utils.Color;
+import com.cleanroommc.modularui.utils.NumberFormat;
+import com.cleanroommc.modularui.widget.Widget;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class GTFluidSlot extends Widget implements Interactable, JeiIngredientProvider {
+
+ private final TextRenderer textRenderer = new TextRenderer();
+ private GTFluidSyncHandler syncHandler;
+
+ public GTFluidSlot() {
+ tooltip().setAutoUpdate(true).setHasTitleMargin(true);
+ tooltipBuilder(tooltip -> {
+ if (!isSynced()) return;
+ var fluid = this.syncHandler.getFluid();
+ if (fluid == null) return;
+
+ tooltip.addLine(fluid.getLocalizedName());
+ tooltip.addLine(IKey.lang("gregtech.fluid.amount", fluid.amount, this.syncHandler.getCapacity()));
+
+ // Add various tooltips from the material
+ List formula = FluidTooltipUtil.getFluidTooltip(fluid);
+ if (formula != null) {
+ for (String s : formula) {
+ if (s.isEmpty()) continue;
+ tooltip.addLine(s);
+ }
+ }
+
+ addIngotMolFluidTooltip(fluid, tooltip);
+ });
+ }
+
+ public static GTFluidSyncHandler sync(IFluidTank tank) {
+ return new GTFluidSyncHandler(tank);
+ }
+
+ @Override
+ public void onInit() {
+ this.textRenderer.setShadow(true);
+ this.textRenderer.setScale(0.5f);
+ this.textRenderer.setColor(Color.WHITE.main);
+ }
+
+ public GTFluidSlot syncHandler(IFluidTank fluidTank) {
+ return syncHandler(new GTFluidSyncHandler(fluidTank));
+ }
+
+ public GTFluidSlot syncHandler(GTFluidSyncHandler syncHandler) {
+ setSyncHandler(syncHandler);
+ this.syncHandler = syncHandler;
+ return this;
+ }
+
+ @Override
+ public void draw(GuiContext context, WidgetTheme widgetTheme) {
+ FluidStack content = this.syncHandler.getFluid();
+ if (content != null) {
+ GuiDraw.drawFluidTexture(content, 1, 1, getArea().w() - 2, getArea().h() - 2, 0);
+
+ String s = NumberFormat.formatWithMaxDigits(getBaseUnitAmount(content.amount)) + getBaseUnit();
+ this.textRenderer.setAlignment(Alignment.CenterRight, getArea().width - 1f);
+ this.textRenderer.setPos(0, 12);
+ this.textRenderer.draw(s);
+ }
+ if (isHovering()) {
+ GlStateManager.colorMask(true, true, true, false);
+ GuiDraw.drawRect(1, 1, getArea().w() - 2, getArea().h() - 2,
+ getWidgetTheme(context.getTheme()).getSlotHoverColor());
+ GlStateManager.colorMask(true, true, true, true);
+ }
+ }
+
+ protected double getBaseUnitAmount(double amount) {
+ return amount / 1000;
+ }
+
+ protected String getBaseUnit() {
+ return "L";
+ }
+
+ @NotNull
+ @Override
+ public Result onMouseTapped(int mouseButton) {
+ if (this.syncHandler.canFillSlot() || this.syncHandler.canDrainSlot()) {
+ this.syncHandler.syncToServer(1, buffer -> buffer.writeBoolean(mouseButton == 0));
+ Interactable.playButtonClickSound();
+ return Result.SUCCESS;
+ }
+ return Result.IGNORE;
+ }
+
+ @Override
+ public WidgetSlotTheme getWidgetTheme(ITheme theme) {
+ return theme.getFluidSlotTheme();
+ }
+
+ @Override
+ public @Nullable Object getIngredient() {
+ return this.syncHandler.getFluid();
+ }
+
+ public static void addIngotMolFluidTooltip(FluidStack fluidStack, Tooltip tooltip) {
+ // Add tooltip showing how many "ingot moles" (increments of 144) this fluid is if shift is held
+ if (TooltipHelper.isShiftDown() && fluidStack.amount > GTValues.L) {
+ int numIngots = fluidStack.amount / GTValues.L;
+ int extra = fluidStack.amount % GTValues.L;
+ String fluidAmount = String.format(" %,d L = %,d * %d L", fluidStack.amount, numIngots, GTValues.L);
+ if (extra != 0) {
+ fluidAmount += String.format(" + %d L", extra);
+ }
+ tooltip.addLine(TextFormatting.GRAY + LocalizationUtils.format("gregtech.gui.amount_raw") + fluidAmount);
+ }
+ }
+}
diff --git a/src/main/java/gregtech/common/mui/widget/InteractableText.java b/src/main/java/gregtech/common/mui/widget/InteractableText.java
new file mode 100644
index 00000000000..eac6936059a
--- /dev/null
+++ b/src/main/java/gregtech/common/mui/widget/InteractableText.java
@@ -0,0 +1,63 @@
+package gregtech.common.mui.widget;
+
+import gregtech.api.util.virtualregistry.VirtualEntry;
+
+import net.minecraft.network.PacketBuffer;
+
+import com.cleanroommc.modularui.api.drawable.IKey;
+import com.cleanroommc.modularui.api.widget.Interactable;
+import com.cleanroommc.modularui.network.NetworkUtils;
+import com.cleanroommc.modularui.utils.Alignment;
+import com.cleanroommc.modularui.utils.Color;
+import com.cleanroommc.modularui.value.sync.SyncHandler;
+import com.cleanroommc.modularui.widgets.TextWidget;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Consumer;
+
+public class InteractableText extends TextWidget implements Interactable {
+
+ private final T entry;
+ private final EntryColorSH syncHandler;
+
+ public InteractableText(T entry, Consumer setter) {
+ super(IKey.str(entry.getColorStr())
+ .alignment(Alignment.CenterLeft)
+ .color(Color.WHITE.darker(1)));
+ this.entry = entry;
+ this.syncHandler = new EntryColorSH(setter);
+ setSyncHandler(this.syncHandler);
+ }
+
+ @NotNull
+ @Override
+ public Result onMousePressed(int mouseButton) {
+ Interactable.playButtonClickSound();
+ this.syncHandler.setColor(this.entry.getColorStr());
+ this.syncHandler.syncToServer(1, buf -> NetworkUtils.writeStringSafe(buf, this.entry.getColorStr()));
+ return Result.SUCCESS;
+ }
+
+ private static class EntryColorSH extends SyncHandler {
+
+ private final Consumer setter;
+
+ private EntryColorSH(Consumer setter) {
+ this.setter = setter;
+ }
+
+ public void setColor(String c) {
+ this.setter.accept(c);
+ }
+
+ @Override
+ public void readOnClient(int id, PacketBuffer buf) {}
+
+ @Override
+ public void readOnServer(int id, PacketBuffer buf) {
+ if (id == 1) {
+ setColor(NetworkUtils.readStringSafe(buf));
+ }
+ }
+ }
+}
diff --git a/src/main/java/gregtech/common/terminal/app/VirtualTankApp.java b/src/main/java/gregtech/common/terminal/app/VirtualTankApp.java
index b6a24a190b9..ed0e63eefac 100644
--- a/src/main/java/gregtech/common/terminal/app/VirtualTankApp.java
+++ b/src/main/java/gregtech/common/terminal/app/VirtualTankApp.java
@@ -12,7 +12,7 @@
import gregtech.api.terminal.os.TerminalTheme;
import gregtech.api.terminal.os.menu.IMenuComponent;
import gregtech.api.util.GTLog;
-import gregtech.api.util.VirtualTankRegistry;
+import gregtech.api.util.virtualregistry.VirtualEnderRegistry;
import gregtech.common.terminal.component.SearchComponent;
import net.minecraft.nbt.NBTTagCompound;
@@ -70,9 +70,8 @@ public AbstractApplication initApp() {
return this;
}
- private List> findVirtualTanks() {
+ private List> findVirtualTanks(Map> tankMap) {
List> result = new LinkedList<>();
- Map> tankMap = VirtualTankRegistry.getTankMap();
for (UUID uuid : tankMap.keySet().stream().sorted(Comparator.nullsLast(UUID::compareTo))
.collect(Collectors.toList())) {
if (uuid == null || uuid.equals(gui.entityPlayer.getUniqueID())) {
@@ -93,9 +92,9 @@ public void detectAndSendChanges() {
}
private void refresh() {
- Map> tankMap = VirtualTankRegistry.getTankMap();
+ Map> tankMap = VirtualEnderRegistry.createTankMap();
Map, FluidStack> access = new HashMap<>();
- for (Pair virtualTankEntry : findVirtualTanks()) {
+ for (Pair virtualTankEntry : findVirtualTanks(tankMap)) {
UUID uuid = virtualTankEntry.getKey();
String key = virtualTankEntry.getValue();
FluidStack fluidStack = tankMap.get(uuid).get(key).getFluid();
@@ -229,7 +228,8 @@ public List getMenuComponents() {
@Override
public String resultDisplay(Pair result) {
- FluidStack fluidStack = VirtualTankRegistry.getTankMap().get(result.getKey()).get(result.getValue()).getFluid();
+ FluidStack fluidStack = VirtualEnderRegistry.createTankMap().get(result.getKey()).get(result.getValue())
+ .getFluid();
return String.format("Lock: %b, ID: %s, Fluid: %s", result.getKey() != null, result.getValue(),
fluidStack == null ? "-" : fluidStack.getLocalizedName());
}
diff --git a/src/main/java/gregtech/core/CoreModule.java b/src/main/java/gregtech/core/CoreModule.java
index 5e80c4b3b31..149c19344ec 100644
--- a/src/main/java/gregtech/core/CoreModule.java
+++ b/src/main/java/gregtech/core/CoreModule.java
@@ -29,9 +29,9 @@
import gregtech.api.unification.material.registry.MarkerMaterialRegistry;
import gregtech.api.util.CapesRegistry;
import gregtech.api.util.Mods;
-import gregtech.api.util.VirtualTankRegistry;
import gregtech.api.util.input.KeyBind;
import gregtech.api.util.oreglob.OreGlob;
+import gregtech.api.util.virtualregistry.VirtualEnderRegistry;
import gregtech.api.worldgen.bedrockFluids.BedrockFluidVeinHandler;
import gregtech.api.worldgen.bedrockFluids.BedrockFluidVeinSaveData;
import gregtech.api.worldgen.config.WorldGenRegistry;
@@ -347,7 +347,7 @@ public void serverStarted(FMLServerStartedEvent event) {
@Override
public void serverStopped(FMLServerStoppedEvent event) {
- VirtualTankRegistry.clearMaps();
+ VirtualEnderRegistry.clearMaps();
CapesRegistry.clearMaps();
}
}
diff --git a/src/main/java/gregtech/integration/opencomputers/drivers/DriverCoverHolder.java b/src/main/java/gregtech/integration/opencomputers/drivers/DriverCoverHolder.java
index be85082485c..b05a8e3f7af 100644
--- a/src/main/java/gregtech/integration/opencomputers/drivers/DriverCoverHolder.java
+++ b/src/main/java/gregtech/integration/opencomputers/drivers/DriverCoverHolder.java
@@ -5,6 +5,7 @@
import gregtech.api.cover.CoverHolder;
import gregtech.api.metatileentity.interfaces.IGregTechTileEntity;
import gregtech.common.covers.*;
+import gregtech.common.covers.ender.CoverEnderFluidLink;
import gregtech.integration.opencomputers.InputValidator;
import gregtech.integration.opencomputers.values.*;
diff --git a/src/main/java/gregtech/integration/opencomputers/values/ValueCoverEnderFluidLink.java b/src/main/java/gregtech/integration/opencomputers/values/ValueCoverEnderFluidLink.java
index 8f919385959..31c8b2ae10d 100644
--- a/src/main/java/gregtech/integration/opencomputers/values/ValueCoverEnderFluidLink.java
+++ b/src/main/java/gregtech/integration/opencomputers/values/ValueCoverEnderFluidLink.java
@@ -1,8 +1,8 @@
package gregtech.integration.opencomputers.values;
import gregtech.api.cover.Cover;
-import gregtech.common.covers.CoverEnderFluidLink;
import gregtech.common.covers.CoverPump.PumpMode;
+import gregtech.common.covers.ender.CoverEnderFluidLink;
import gregtech.integration.opencomputers.InputValidator;
import net.minecraft.util.EnumFacing;
diff --git a/src/main/java/gregtech/integration/theoneprobe/provider/CoverInfoProvider.java b/src/main/java/gregtech/integration/theoneprobe/provider/CoverInfoProvider.java
index 0aebf88036a..377ff7a51d7 100644
--- a/src/main/java/gregtech/integration/theoneprobe/provider/CoverInfoProvider.java
+++ b/src/main/java/gregtech/integration/theoneprobe/provider/CoverInfoProvider.java
@@ -6,6 +6,7 @@
import gregtech.api.cover.CoverHolder;
import gregtech.api.util.TextFormattingUtil;
import gregtech.common.covers.*;
+import gregtech.common.covers.ender.CoverEnderFluidLink;
import gregtech.common.covers.filter.*;
import net.minecraft.entity.player.EntityPlayer;
@@ -181,8 +182,8 @@ private static void fluidFilterInfo(@NotNull IProbeInfo probeInfo, @NotNull Cove
* @param enderFluidLink the ender fluid link cover to get data from
*/
private static void enderFluidLinkInfo(@NotNull IProbeInfo probeInfo, @NotNull CoverEnderFluidLink enderFluidLink) {
- transferRateText(probeInfo, enderFluidLink.getPumpMode(), " " + lang("cover.bucket.mode.milli_bucket_rate"),
- enderFluidLink.isIOEnabled() ? CoverEnderFluidLink.TRANSFER_RATE : 0);
+ transferRateText(probeInfo, enderFluidLink.getPumpMode(), " " + lang("cover.ender_fluid_link.transfer_unit"),
+ enderFluidLink.isIoEnabled() ? CoverEnderFluidLink.TRANSFER_RATE : 0);
fluidFilterText(probeInfo, enderFluidLink.getFluidFilterContainer().getFilter());
if (!enderFluidLink.getColorStr().isEmpty()) {
diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang
index 8576e93db24..042607af612 100644
--- a/src/main/resources/assets/gregtech/lang/en_us.lang
+++ b/src/main/resources/assets/gregtech/lang/en_us.lang
@@ -1358,6 +1358,13 @@ cover.ender_fluid_link.iomode.disabled=I/O Disabled
cover.ender_fluid_link.private.tooltip.disabled=Switch to private tank mode\nPrivate mode uses the player who originally placed the cover
cover.ender_fluid_link.private.tooltip.enabled=Switch to public tank mode
cover.ender_fluid_link.incomplete_hex=Inputted color is incomplete!/nIt will be applied once complete (all 8 hex digits)/nClosing the gui will lose edits!
+cover.ender_fluid_link.transfer_unit=L/t
+
+cover.generic.ender.known_channels=Known Channels
+cover.generic.ender.open_selector=Open Entry Selector
+cover.generic.ender.set_description.tooltip=Set Description
+cover.generic.ender.set_description.title=Set Description [%s]
+cover.generic.ender.delete_entry=Delete Entry
cover.generic.advanced_detector.latched=Latched
cover.generic.advanced_detector.continuous=Continuous
diff --git a/src/main/resources/assets/gregtech/textures/gui/overlay/menu_overlay.png b/src/main/resources/assets/gregtech/textures/gui/overlay/menu_overlay.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc166fac7e49d3b04f74b59ef7ab6fef26a40d0d
GIT binary patch
literal 130
zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|#^NA%Cx&(BWL^R}Hl8kyAr`&K
z2@
Date: Thu, 19 Sep 2024 08:00:44 +0400
Subject: [PATCH 2/7] Update ru_ru.lang and Initial Ukranian langluage (#2602)
Co-authored-by: Western01
Co-authored-by: German Khris
---
.../resources/assets/gregtech/lang/ru_ru.lang | 38 +-
.../resources/assets/gregtech/lang/uk_UA.lang | 1090 +++++++++++++++++
2 files changed, 1120 insertions(+), 8 deletions(-)
create mode 100644 src/main/resources/assets/gregtech/lang/uk_UA.lang
diff --git a/src/main/resources/assets/gregtech/lang/ru_ru.lang b/src/main/resources/assets/gregtech/lang/ru_ru.lang
index f8bfe1a7604..32e4120f240 100644
--- a/src/main/resources/assets/gregtech/lang/ru_ru.lang
+++ b/src/main/resources/assets/gregtech/lang/ru_ru.lang
@@ -39,7 +39,7 @@ enchantment.disjunction=Разъединение
gregtech.machine.steam_grinder.name=Паровой измельчитель
gregtech.multiblock.steam_grinder.description=Многоблочный измельчитель в паровой эпохе. Требует как минимум 14 бронзовых машинных корпусов. Может использовать только паровые люки.
gregtech.multiblock.steam.low_steam=Недостаточно пара для работы!
-gregtech.multiblock.steam.steam_stored=Пар: %s / %s mB
+gregtech.multiblock.steam.steam_stored=Пар: %s
gregtech.machine.steam_hatch.name=Паровой люк
gregtech.machine.steam.steam_hatch.tooltip=§eПринимает жидкости: §fПар
gregtech.machine.steam_import_bus.name=Паровой входной люк
@@ -1315,7 +1315,7 @@ gregtech.material.hydrogen=Водород
gregtech.material.helium=Гелий
gregtech.material.helium_3=Гелий-3
gregtech.material.indium=Индий
-gregtech.material.iodine=Иод
+gregtech.material.iodine=Йод
gregtech.material.iridium=Иридий
gregtech.material.iron=Железо
gregtech.material.krypton=Криптон
@@ -1783,9 +1783,9 @@ gregtech.material.wood=Дерево
gregtech.material.treated_wood=Обработанное дерево
gregtech.material.paper=Бумага
gregtech.material.fish_oil=Рыбий жир
-gregtech.material.ruby_slurry=Рубиновый шлам
-gregtech.material.sapphire_slurry=Сапфирный шлам
-gregtech.material.green_sapphire_slurry=Шлам зелёного сапфира
+gregtech.material.ruby_slurry=Рубиновая суспензия
+gregtech.material.sapphire_slurry=Сапфировая суспензия
+gregtech.material.green_sapphire_slurry=Суспензия зелёного сапфира
gregtech.material.dye_black=Черный краситель
gregtech.material.dye_red=Красный краситель
gregtech.material.dye_green=Зеленый краситель
@@ -5038,7 +5038,7 @@ gregtech.multiblock.hpca.warning_structure_header=Подсказки по стр
gregtech.multiblock.hpca.warning_multiple_bridges=- Множество мостов в структуре (не дают дополнительных преимущество)
gregtech.multiblock.hpca.warning_no_computation=- Не проводятся вычисления
gregtech.multiblock.hpca.warning_low_cooling=- Не достаточно хладогента
-gregtech.command.usage=Применение: /gregtech
+gregtech.command.usage=Применение: /gregtech
gregtech.command.worldgen.usage=Применение: /gregtech worldgen
gregtech.command.worldgen.reload.usage=Применение: /gregtech worldgen reload
gregtech.command.worldgen.reload.success=Генератор мира успешно перезагрузился из настроек.
@@ -5934,7 +5934,7 @@ gregtech.machine.me.stocking_item.tooltip=Извлекает предметы н
gregtech.machine.me_import_item_hatch.configs.tooltip=Держит 16 предметов в наличии
tile.gt_explosive.breaking_tooltip=При обычной добыче взрывается, добудьте с SHIFT, чтобы забрать обратно
gregtech.machine.me.stocking_fluid.tooltip=Извлекает жидкости непосредственно из сети ME
-gregtech.machine.me.copy_paste.tooltip=ЛКС с Флешкой для копирования, ПКМ для применения
+gregtech.machine.me.copy_paste.tooltip=ЛКМ с Флешкой для копирования, ПКМ для применения
gregtech.machine.me.import_copy_settings=Настройки сохранены в Флешку
gregtech.machine.me.import_paste_settings=Настройки из Флешки применены
gregtech.machine.me.fluid_import.data_stick.name=§oНастройки ME Накопительного жидкостного люка
@@ -5951,7 +5951,7 @@ tile.gt_explosive.lighting_tooltip=Нельзя зажечь с помощью
gregtech.multiblock.power_substation.average_in_hover=Средний приход EU/t в внутреннее хранилище вашей Силовой Подстанции
gregtech.machine.me.stocking_item.tooltip.2=Авто-вытягивание из МЕ сети будет автоматически пополнять первые 16 предметов в МЕ сети, обновляясь раз в 5 сек.
gregtech.machine.me.stocking_fluid.tooltip.2=Авто-вытягивание из МЕ сети будет автоматически пополнять первые 16 слотов жидкости в МЕ сети, обновляясь раз в 5 сек.
-gregtech.gui.config_slot.auto_pull_managed=§4Отключено:§7 Управляется Авто-вытягивание
+gregtech.gui.config_slot.auto_pull_managed=§4Отключено:§7 Управляется Авто-вытягиванием
tile.itnt.drops_tooltip=Намного мощнее, чем TNT. Все взорванные блоки выпадают как предметы
gregtech.multiblock.cleanroom.low_tier=Уровень вольтажа слишком низкий, требуется %s или выше!
gregtech.gui.item_auto_input.tooltip.disabled=Авто. ввод предметов выключен
@@ -5981,3 +5981,25 @@ gregtech.machine.me.stocking_auto_pull_enabled=Авто-вытягивание
cover.machine_controller.this_cover=§cЭто улучшение
cover.machine_controller.cover_not_controllable=§cНет управляемых улучшений
cover.machine_controller.control=Управление:
+gregtech.material.ilmenite_slag=Ильменитовый шлак
+gregtech.material.zirconia=Оксид циркония
+gregtech.command.datafix.usage=Применение: /gregtech datafix
+gregtech.material.decalcified_bauxite_sludge=Декальцинированный шлам боксита
+gregtech.material.zircon=Циркон
+gregtech.material.zirconium_tetrachloride=Тетрахлорид циркония
+gregtech.material.hafnia=Гафнии
+gregtech.material.hafnium_tetrachloride=Тетрахлорид гафния
+gregtech.material.zircaloy_4=Циркалой-4
+gregtech.material.inconel_718=Инконель-718
+gregtech.material.bauxite_sludge=Шлам боксита
+gregtech.material.bauxite_slurry=Бокситовая суспензия
+gregtech.material.cracked_bauxite_slurry=Бокситовая суспензия прошедшая крекинг
+gregtech.material.bauxite_slag=Бокситовый шлак
+gregtech.command.datafix.bqu.usage=Применение: /gregtech datafix bqu [confirm]
+gregtech.command.datafix.bqu.backup=Скопируйте ваши сохранения и папку настроек BQu, а после перезапустите с 'confirm' аргументов
+gregtech.command.datafix.bqu.start=Начинается перенос BQu Базы данных Квестов...
+gregtech.command.datafix.bqu.complete=Закончен перенос Базы данных Квестов
+gregtech.command.datafix.bqu.failed=Перенос Базы данных Квестов был произведен с ошибкой. Восстановите ваши сохранения!
+behavior.tricorder.mte_owner=Владелец: %s
+behavior.tricorder.mte_owner_offline=Владелец Не в сети или Не в этом мире!
+behavior.tricorder.mte_owner_null=Это установлено не игроком!
diff --git a/src/main/resources/assets/gregtech/lang/uk_UA.lang b/src/main/resources/assets/gregtech/lang/uk_UA.lang
new file mode 100644
index 00000000000..46667cc7db0
--- /dev/null
+++ b/src/main/resources/assets/gregtech/lang/uk_UA.lang
@@ -0,0 +1,1090 @@
+
+
+death.attack.heat=
+death.attack.chemical=%s потрапив у хімічний інцидент
+death.attack.electric=%s був убитий струмом
+death.attack.radiation=%s тепер світиться від радості
+death.attack.turbine=%s засунув голову в турбіну
+death.attack.explosion=%s вибухнув
+death.attack.explosion.player=%s вибухнув з допомогою %s
+death.attack.heat.player=%s був зварений живцем з допомогою %s
+death.attack.shovel=%s було викопано з допомогою %s
+death.attack.axe=%s було порубано на шматки з допомогою %s
+death.attack.hammer=%s був розчавлений з допомогою %s
+death.attack.mallet=%s був забитий до смерті з допомогою %s
+death.attack.mining_hammer=%s був помилково прийнятий за руду %s
+death.attack.wrench=%s вдарив %s гайковим ключем!
+death.attack.frost=%s досліджував кріогенні технології
+death.attack.mortar=%s було розтерто на порох з допомогою %s
+death.attack.wire_cutter=кабель життєзабезпечення %s був перерізаний %s
+death.attack.knife=%s був ніжно вдарений ножем з допомогою %s
+death.attack.drill_lv=%s був пробурений при напрузі 32V з допомогою %s
+death.attack.wrench_iv=До планів %s несподівано був доданий гайковий ключ %s
+death.attack.buzzsaw=%s був розпиляний з допомогою %s
+enchantment.disjunction=Роз'єднання
+gregtech.machine.steam_grinder.name=Парова дробарка
+death.attack.drill_hv=%s був пробурений при напрузі 512V з допомогою %s
+death.attack.drill_iv=%s був пробурений при напрузі 8192V з допомогою %s
+death.attack.chainsaw_lv=%s був розпиляний з допомогою %s
+gregtech.multiblock.steam.low_steam=Не вистачає пари для роботи!
+gregtech.machine.steam_hatch.name=Паровий люк
+gregtech.multiblock.steam.steam_stored=Пар: %s
+gregtech.machine.steam.steam_hatch.tooltip=§eМожливі рідини: §fПар
+gregtech.machine.steam_import_bus.name=Парова вхідна шина
+gregtech.machine.steam_export_bus.name=Парови вихідна шина
+gregtech.machine.steam_oven.name=Парова мультиплавильна піч
+gregtech.multiblock.require_steam_parts=Потребує парові люки та шини!
+gregtech.multiblock.steam_.duration_modifier=Потребує в §f1.5x §7більше часу, не залежить від кількості предметів.
+gregtech.top.energy_production=Виготовляє
+gregtech.top.transform_down=Знижувати
+gregtech.top.transform_input=Вхід:
+gregtech.top.transform_output=Вихід:
+gregtech.top.steam_heating_up=Нагрівання
+gregtech.top.steam_no_water=Немає води
+gregtech.top.convert_fe=Конвертація §cFE§r -> §eEU§r
+gregtech.top.invalid_structure=Структура незавершена
+gregtech.top.obstructed_structure=Структура заблокована
+gregtech.top.maintenance_fixed=Технічне обслуговування непотрібне
+gregtech.top.maintenance.wrench=Труба ослаблена
+gregtech.top.maintenance.screwdriver=Гвинти ослаблені
+gregtech.top.maintenance.hard_hammer=Обшивка має вм'ятини
+gregtech.top.maintenance.crowbar=Щось там не повинно бути
+gregtech.top.mode.export=Експортуємо
+gregtech.top.unit.items=Предмети
+gregtech.top.unit.fluid_milibuckets=МЛ
+gregtech.top.unit.fluid_buckets=Л
+gregtech.top.block_drops=Випадає
+gregtech.top.ld_pipe_incomplete=Незавершений трубопровід
+gregtech.top.ld_pipe_length=Довжина:
+option.gregtech.converter=Енергетичні конвертори
+option.gregtech.diode=Діоди
+option.gregtech.energy=Енергосховища
+option.gregtech.block_lamp=Лампи
+option.gregtech.multi_recipemap=Режими роботи
+option.gregtech.multiblock=Багатоблочні конструкції
+option.gregtech.primitive_pump=Примітивний насос
+option.gregtech.transformer=Трансформатори
+gregtech.waila.progress_idle=Холостий
+gregtech.waila.progress_sec=Прогрес: %d s / %d s
+gregtech.waila.progress_computation=Розрахунок: %s / %s
+gregtech.multiblock.title=Схема багатоблокової структури
+gregtech.multiblock.assembly_line.description=Складальна лінія - це велика багатоблочна конструкція, що складається з 5 до 16 "шматочків". Теоретично, це велика складальна машина, що використовується для виготовлення покращених компонентів.
+gregtech.multiblock.fusion_reactor.uv.description=Термоядерний реактор модель 3 - це велика багатоблочна конструкція, яка використовується для злиття елементів у більш важкі. Може використовувати лише енергетичні люки типу UV. З кожним люком буфер енергії збільшується на 40 млн EU, і має максимум у 640 млн EU.
+gregtech.multiblock.fusion_reactor.heat=Тепло: %s
+metaitem.coin.doge.name=Догкоін
+metaitem.shape.empty.name=Порожня форма
+metaitem.dynamite.name=Динаміт
+metaitem.power_unit.lv.name=Блок живлення (LV)
+metaitem.power_unit.mv.name=Блок живлення (MV)
+metaitem.power_unit.hv.name=Блок живлення (HV)
+metaitem.nano_saber.name=Наношабля
+metaitem.nano_saber.tooltip=Ryujin no ken wo kurae!
+metaitem.shape.mold.plate.tooltip=Форма для виготовлення пластин
+metaitem.shape.mold.plate.name=Форма (Пластина)
+metaitem.shape.mold.gear.tooltip=Форма для виготовлення шестерень
+metaitem.shape.mold.gear.name=Форма (Шестерня)
+metaitem.shape.mold.bottle.name=Форма (Пляшка)
+metaitem.shape.mold.bottle.tooltip=Форма для виготовлення пляшок
+metaitem.shape.mold.ingot.name=Форма (Злиток)
+metaitem.shape.mold.ball.name=Форма (Куля)
+metaitem.shape.mold.ball.tooltip=Форма для виготовлення куль
+metaitem.shape.mold.block.name=Форма (Блок)
+metaitem.shape.mold.nugget.name=Форма (самородки)
+metaitem.shape.mold.cylinder.name=Форма (Циліндр)
+metaitem.shape.mold.name.name=Форма (Назва)
+metaitem.shape.mold.cylinder.tooltip=Форма для формування циліндрів
+metaitem.shape.mold.gear.small.tooltip=Форма для виготовлення малих шестерень
+metaitem.shape.mold.rotor.name=Форма (Ротор)
+metaitem.shape.extruder.plate.name=Форма екструдера (пластина)
+metaitem.shape.extruder.plate.tooltip=Форма екструдера для виготовлення пластин
+metaitem.shape.extruder.bolt.name=Форма екструдера (Болт)
+metaitem.shape.extruder.ring.tooltip=Форма екструдера для виготовлення кілець
+metaitem.shape.extruder.cell.name=Форма екструдера (Капсула)
+metaitem.shape.extruder.casing.name=Форма екструдера (Корпус)
+metaitem.shape.extruder.pipe.tiny.name=Форма екструдера (Крихітна трубка)
+metaitem.shape.extruder.pipe.small.name=Форма екструдера (маленька труба)
+metaitem.shape.extruder.pipe.normal.tooltip=Форма екструдера для виготовлення труб
+metaitem.shape.extruder.pipe.large.name=Форма екструдера (Велика труба)
+metaitem.shape.extruder.pipe.huge.tooltip=Форма екструдера для виготовлення величезних труб
+metaitem.shape.extruder.block.name=Форма екструдера (Блок)
+metaitem.shape.extruder.block.tooltip=Форма екструдера для виготовлення блоків
+metaitem.shape.extruder.shovel.tooltip=Форма екструдера для виготовлення лопат
+metaitem.shape.extruder.hoe.name=Форма екструдера (Головка мотики)
+metaitem.shape.extruder.hoe.tooltip=Форма екструдера для виготовлення мотик
+metaitem.shape.extruder.saw.name=Форма екструдера (Пильний диск)
+metaitem.shape.extruder.saw.tooltip=Форма екструдера для виготовлення пилок
+metaitem.shape.extruder.gear.name=Форма екструдера (Шестерня)
+death.attack.pickaxe=мізки %s було вибито з допомогою %s
+death.attack.hoe=%s був проораний з допомогою %s
+death.attack.wrench_hv=Труби %s були послаблені з допомогою %s
+gregtech.multiblock.steam_grinder.description=Багатоблочний подрібнювач парової епохи. Для побудови потрібно щонайменше 14 бронзових корпусів. Не може використовувати звичайні вхідні/вихідні шини, або рідині люки. Може використовувати тільки парові люки.
+gregtech.multiblock.steam_oven.description=Мультиплавильна піч парової епохи. Для побудови потрібно щонайменше 6 бронзових корпусів. Не може використовувати звичайні вхідні/вихідні шини, або рідині люки. Може використовувати тільки парові люки. Паровий люк має бути на першому рівні, та не має бути більше одного.
+gregtech.top.working_disabled=Робота призупинена
+gregtech.top.transform_up=Підвищує
+gregtech.top.convert_eu=Конвертація §eEU§r -> §cFE§r
+gregtech.top.valid_structure=Структура завершена
+gregtech.top.maintenance.wire_cutter=Дроти перегоріли
+gregtech.top.mode.import=Імпортуємо
+gregtech.top.ld_pipe_no_network=Не знайдено жодного трубопроводу
+gregtech.top.ld_pipe_connected=Трубопровід під'єднано
+gregtech.top.ld_pipe_output=Вихід
+gregtech.top.ld_pipe_input_endpoint=Кінцева точка входу:
+gregtech.top.ld_pipe_output_endpoint=Кінцева точка виходу:
+option.gregtech.controllable=Керовані машини
+option.gregtech.maintenance=Проблеми з технічним обслуговуванням
+option.gregtech.recipe_logic=Рецепти
+option.gregtech.steam_boiler=Парові котли
+gregtech.waila.energy_stored=Енергія: %d EU / %d EU
+death.attack.spade=%s був розкопаний з допомогою %s
+death.attack.screwdriver_lv=Гвинти %s були відкручені з допомогою %s
+gregtech.top.energy_consumption=Використовує
+gregtech.top.maintenance_broken=Технічне обслуговування потрібне
+gregtech.top.maintenance.soft_mallet=Щось заклинило
+gregtech.top.primitive_pump_production=Виробництво:
+gregtech.top.filter.label=Фільтр:
+gregtech.top.link_cover.color=Колір:
+gregtech.top.ld_pipe_input=Вхід
+option.gregtech.block_ore=Рудні блоки
+option.gregtech.workable=Механізми
+gregtech.waila.progress_tick=Прогрес: %d t / %d t
+gregtech.machine.steam_bus.tooltip=Не працює з не паровими багатоблочними конструкціями
+metaitem.shape.mold.name.tooltip=Форма для іменування предметів у формувальному пресі (перейменувати форму за допомогою ковадла)
+metaitem.shape.mold.gear.small.name=Форма (Мала шестерня)
+metaitem.shape.mold.rotor.tooltip=Форма для виготовлення роторів
+metaitem.shape.extruder.rod.name=Форма екструдера (Cтержень)
+metaitem.shape.extruder.ingot.tooltip=Форма екструдера для, зачекайте, хіба ми не можемо просто використовувати піч?
+metaitem.shape.extruder.wire.tooltip=Форма екструдера для виготовлення дротів
+metaitem.shape.extruder.pipe.tiny.tooltip=Форма екструдера для виготовлення крихітних труб
+metaitem.shape.extruder.pipe.small.tooltip=Форма екструдера для виготовлення малих труб
+metaitem.shape.extruder.pipe.normal.name=Форма екструдера (Труба)
+metaitem.shape.extruder.pipe.large.tooltip=Форма екструдера для виготовлення великих труб
+metaitem.shape.extruder.pipe.huge.name=Форма екструдера (Величезна труба)
+metaitem.shape.extruder.sword.tooltip=Форма екструдера для виготовлення мечів
+metaitem.shape.extruder.pickaxe.name=Форма екструдера (Головка кайла)
+metaitem.shape.extruder.pickaxe.tooltip=Форма екструдера для виготовлення кайла
+gregtech.multiblock.primitive_blast_furnace.bronze.description=Примітивна доменна піч (ПДП) це багатоблочна структура, що використовуєть для виготовлення сталі на початку гри. Хоча вона і не дуже швидка, вона забезпечить вам сталь для перших кроків.
+gregtech.multiblock.coke_oven.description=Коксова піч - це багатоблочна конструкція, яка використовується для отриманя коксу та креозоту на початку гри. Вона не потребує палива і має внутрішній резервуар на 32 відра креозоту. Доступ до інвентарю можна отримати через люк коксової печі.
+gregtech.multiblock.vacuum_freezer.description=Вакуумна морозильна камера - це багатоблочна структура, яка в більшості випадків використовується для охолоджування гарячих злитків до їхньоніх звичайних температур. Також може заморожувати інші речовини, до прикладу вода.
+gregtech.multiblock.implosion_compressor.description=Імплохійний компресор - це багатоблочна структура яка використовує вибухівки щоб перетворити пил на відповідні дорогоцінні камені.
+gregtech.multiblock.pyrolyse_oven.description=Піролізна піч - це багатоблочна конструкція, яка використовується для перетворення колод на деревне вугілля та креозот, або золу та тяжку нафту.
+gregtech.multiblock.cracker.description=Крекінгова установка - це багатоблочна конструкція, яка використовується для перетворення легкого та важкаго палина на їхні потріскані варіанти.
+gregtech.multiblock.large_combustion_engine.description=Великий двигун внутрішнього згоряння - це багатоблочна конструкція, яка діє як генератор внетрішнього згоряння для вироблення EV енергіє.
+metaitem.shape.mold.anvil.name=Форма (Ковадло)
+metaitem.shape.mold.anvil.tooltip=Форма для формування ковадла
+metaitem.shape.extruder.rod.tooltip=Форма екструдера для виготовлення стержнів
+metaitem.shape.extruder.bolt.tooltip=Форма екструдера для виготовлення болтів
+metaitem.shape.extruder.ring.name=Форма екструдера (Кільце)
+metaitem.shape.extruder.cell.tooltip=Форма екструдера для виготовлення капсул
+metaitem.shape.extruder.ingot.name=Форма екструдера (злиток)
+metaitem.shape.extruder.wire.name=Форма екструдера (Дріт)
+metaitem.shape.extruder.casing.tooltip=Форма екструдера для виготовлення корпусів
+metaitem.shape.extruder.sword.name=Форма екструдера (Лезо меча)
+metaitem.shape.extruder.shovel.name=Форма екструдера (Головка лопати)
+metaitem.shape.extruder.axe.name=Форма екструдера (Головка сокири)
+metaitem.shape.extruder.axe.tooltip=Форма екструдера для виготовлення сокир
+death.attack.file=%s був заокруглений до сметрі з допомогою %s
+death.attack.drill_ev=%s був пробурений при напрузі 2048V з допомогою %s
+death.attack.butchery_knife=%s був перетворений у фарш з допомогою %s
+death.attack.drill_mv=%s був пробурений при напрузі 128V з допомогою %s
+death.attack.wrench_lv=Труби %s були ослаблені з допомогою %s
+gregtech.multiblock.large_turbine.description=Великі турбіни - це багатоблочна конструкція яка генерую електроенергію з пари, газів, і плазми шляхом обертання ротора турбіни. Вихід енергії залежить від ефективності ротора та поточної швидкості турбіни. У центрі конструкції використовуються корпуси коробки передач.
+metaitem.shape.extruder.hammer.name=Форма екструдера (Молоткова головка)
+metaitem.shape.extruder.hammer.tooltip=Форма екструдера для виготовлення молотків
+metaitem.shape.extruder.file.tooltip=Форма екструдера для воготовлення напилка
+metaitem.shape.extruder.file.name=Форма екструдера (Головка напилка)
+metaitem.shape.extruder.gear.tooltip=Форма екструдера для виготовлення шестерень
+metaitem.shape.extruder.bottle.name=Форма екструдера (Пляшка)
+death.attack.scythe=Душу %s було викрадено з допомогою %s
+gregtech.multiblock.extreme_combustion_engine.description=Екстремальний двигун внутрішнього згорання - це багатоблочна конструкція, яка діє як генератор згоряння для IV рівня напруги.
+gregtech.multiblock.distillation_tower.description=Дистиляціна вежа - це багатоблочана конструкція, яка використовується для перегонки різних видів нафти та деяких побічних продуктів. Кожен шар починаючи з другого повинен мати рівно один вихідний люк. Нижній шар може виводити продукти і вводити рідини в будь-якому положенні.
+gregtech.multiblock.electric_blast_furnace.description=Електрична доменна піч (ЕДП) - це багатоблочна конструкція, яка використовується для виплавки сплавів, готових металів та переробки сирих. Вона необхідна для отримання високоякісних сплавів і металів, таких як алюміній, нержавіюча сталь, титат і сплав наквади.
+gregtech.multiblock.multi_furnace.description=Мультиплавильна піч - це багатоблочна конструкція, яка використовується для виплавлення великої кількості предметів. Різні рівні котушок забезпечують підвищення швидкості та енергоефективності. 32 - це базова кількість предметів, що виплавляються за операцію, яке можна збільшити, використовуючи котушки вищого рівня.
+gregtech.multiblock.large_boiler.description=Великі котли - це багатоблочна структура, яка виробляє пар за допомогою енергії та води. Джерелом енергії є будь-яке тверде паливо з певним часом горіння або дизельне/напіврідке паливо. Може бути сповільнене заради зменшення кількості пари та потрібного палива.
+gregtech.multiblock.fusion_reactor.luv.description=Термоядерний реактор модель 1 - це велика багатоблочна конструкція, яка використовується для злиття елементів у більш важкі. Може використовувати лише енергетичні люки типу LuV, ZPM, і UV. З кожним люком буфер енергії збільшується на 10 млн EU, і має максимум у 160 млн EU.
+gregtech.multiblock.fusion_reactor.zpm.description=Термоядерний реактор модель 2 - це велика багатоблочна конструкція, яка використовується для злиття елементів у більш важкі. Може використовувати лише енергетичні люки типу ZPM і UV. З кожним люком буфер енергії збільшується на 20 млн EU, і має максимум у 320 млн EU.
+gregtech.multiblock.large_chemical_reactor.description=Великий хімічний реактор виконує хімічні реакції зі 100%% енергоефективністю. Розгін збільшує швидкість і евергію в 4 рази. Багатоблочна конструкція потребує рівно 1 купронікелевий блок, який повинен бути розміщений поруч з копрусом ПТФЕ труби, розташованим в центрі.
+metaitem.credit.platinum.tooltip=512 Кредитів
+metaitem.credit.osmium.tooltip=4096 Кредити
+metaitem.credit.naquadah.name=Наквадовий Кредит
+metaitem.coin.gold.ancient.name=Старовинна золота монета
+metaitem.coin.gold.ancient.tooltip=Знайдено в стародавніх руїнах
+metaitem.power_unit.iv.name=Блок живлення (IV)
+metaitem.shape.mold.casing.tooltip=Форма для виготовлення корпусів
+metaitem.shape.mold.block.tooltip=Форма для виготовлення блоків
+gregtech.multiblock.primitive_water_pump.description=Примітивна водяна помпа - це багатоблочна конструкція до парової ери, яка збирає води один раз на секунду, залежно в якому біома. Вона може використовувати помповий, ULV або LV вихідний люк, збільшуючи кількість води на рівень. Розраховується за формулою: коефіцієнь біома * множник люка
+metaitem.credit.osmium.name=Осмійські Кредит
+metaitem.credit.naquadah.tooltip=32768 Кредити
+metaitem.credit.neutronium.name=Нейтронний кредит
+metaitem.credit.neutronium.tooltip=262144 Кредити
+metaitem.coin.chocolate.name=Шоколадна монетка
+metaitem.coin.chocolate.tooltip=Загорнутий у золото
+metaitem.shape.empty.tooltip=Сировина для виготовлення прес-форм та екструзійних форм
+metaitem.power_unit.ev.name=Блок живлення (EV)
+metaitem.shape.mold.credit.name=Форма (Монета)
+metaitem.shape.mold.credit.tooltip=Безпечна форма для виготовлення монет (не загуби!)
+metaitem.shape.mold.casing.name=Форма (Корпус)
+metaitem.shape.mold.ingot.tooltip=Форма для виготовлення злитків
+metaitem.shape.mold.nugget.tooltip=Форма для виготовлення самородків
+gregtech.multiblock.primitive_water_pump.extra2=Множники люків:/n Люк насоса: 1x/n Вихідний люк ULV: 2x/n Вихідний люк LV: 4x/n/nПід час дощу в біомі насоса загальне виробництво води збільшується на 50%%.
+gregtech.multiblock.processing_array.description=Оброблювальний масив об'єднує до 16 одноблочних машин в один мультиблок, що значно полегшує автоматизацію.
+item.invalid.name=Некоректний предмет
+fluid.empty=Порожньо
+gregtech.tooltip.hold_shift=Утримуйте SHIFT, щоб дізнатися більше
+gregtech.tooltip.hold_ctrl=Утримуйте CTRL, щоб дізнатися більше
+gregtech.tooltip.tool_fluid_hold_shift=Утримуйте SHIFT, щоб відобразити інформацію про рідину та інструмент
+metaitem.generic.fluid_container.tooltip=%,d/%,dЛ %s
+metaitem.generic.electric_item.tooltip=%,d/%,d EU - Рівень %s
+metaitem.electric.discharge_mode.enabled=§eУвімкнено режим розрядки
+metaitem.dust.tooltip.purify=Киньте в Казан, щоб отримати чистий пил
+metaitem.int_circuit.configuration=§aНалаштоване значення: §f%d§7
+metaitem.credit.copper.tooltip=0.125 Кредитів
+metaitem.credit.silver.name=Срібний кредит
+metaitem.credit.silver.tooltip=8 кредитів
+metaitem.credit.gold.name=Золотий кредит
+metaitem.credit.gold.tooltip=64 Кредитів
+metaitem.credit.platinum.name=Платиновий кредит
+metaitem.shape.extruder.rod_long.tooltip=Форма екструдера для виготовлення довгих стержнів
+metaitem.shape.extruder.rod_long.name=Форма екструдера (Довгий стержень)
+metaitem.spray.empty.name=Балончик (порожній)
+metaitem.spray.empty.tooltip=Можна наповнювати спреями різних кольорів
+
+# Fluid Cells
+metaitem.fluid_cell.empty=Порожньо
+metaitem.fluid_cell.name=%s Капсула
+metaitem.fluid_cell.universal.name=%s Універсальна капсула
+metaitem.large_fluid_cell.steel.name=%s Сталева капсула
+metaitem.fluid_cell.glass_vial.name=%s Пробірка
+metaitem.large_fluid_cell.titanium.name=%s Титанова капсула
+metaitem.spray.solvent.name=Балончик (розчинник)
+metaitem.spray.can.dyes.orange.name=Балончик (помаранчевий)
+metaitem.spray.can.dyes.purple.name=Балончик (фіолетовий)
+metaitem.tool.matches.name=Сірник
+metaitem.tool.lighter.platinum.name=Платинова запальничка
+metaitem.battery.hull.hv.name=Великий корпус батареї
+metaitem.battery.hull.ev.name=Малий корпус ванадієвої батареї
+metaitem.battery.hull.zpm.name=Корпус середньої наквадівої батареї
+metaitem.battery.hull.zpm.tooltip=Порожній §fZPM §7корпус батареї
+metaitem.battery.hull.uv.name=Корпус великої наквадівої батареї
+metaitem.battery.hull.uv.tooltip=Порожній §3UV §7корпус батареї
+metaitem.battery.charge_time=§aЗберігає %,d%s електроенергії
+metaitem.battery.charge_unit.minute=хв
+metaitem.battery.charge_unit.hour=год
+metaitem.battery.re.ulv.tantalum.name=Танталовий конденсатор
+metaitem.battery.re.lv.cadmium.name=Маленька кадмієва батарея
+metaitem.battery.re.lv.cadmium.tooltip=Багаторазова батарея
+metaitem.battery.re.lv.lithium.name=Маленька літієва батарея
+metaitem.battery.re.mv.cadmium.tooltip=Багаторазова батарея
+metaitem.battery.re.mv.sodium.tooltip=Багаторазова батарея
+metaitem.battery.re.hv.cadmium.name=Велика кадмієва батарея
+metaitem.battery.re.hv.cadmium.tooltip=Багаторазова батарея
+metaitem.battery.re.hv.lithium.name=Велика літієва батарея
+metaitem.battery.re.hv.sodium.name=Велика натрієва батарея
+metaitem.battery.ev.vanadium.name=Маленька ванадієва батарея
+metaitem.battery.iv.vanadium.name=Середня ванадієва батарея
+metaitem.battery.luv.vanadium.name=Велика ванадієва батарея
+metaitem.battery.luv.vanadium.tooltip=Багаторазова батарея
+metaitem.battery.uv.naquadria.name=Велика наквадрієва батарея
+metaitem.energy_crystal.name=Енергетичний кристал
+metaitem.energy.lapotronic_orb.tooltip=Багаторазова батарея
+metaitem.energy.lapotronic_orb_cluster.name=Лапотронний кластер енергетичних куль
+metaitem.energy.module.name=Енергетичний модуль
+metaitem.energy.cluster.name=Енергетичний кластер
+metaitem.max.battery.tooltip=Зарядіть це, щоб виграти Minecraft
+metaitem.electric.motor.luv.name=Електродвигун LuV
+metaitem.electric.motor.zpm.name=Електродвигун ZPM
+metaitem.electric.motor.uev.name=Електродвигун UEV
+metaitem.electric.motor.uxv.name=Електродвигун UXV
+metaitem.electric.pump.ev.name=Електронасос EV
+metaitem.electric.pump.iv.name=Електронасос IV
+metaitem.electric.pump.uev.name=Електронасос UEV
+metaitem.electric.pump.uxv.name=Електронасос UXV
+metaitem.fluid.regulator.lv.name=Регулятор рідини LV
+metaitem.fluid.regulator.mv.name=Регулятор рідини MV
+metaitem.fluid.regulator.luv.name=Регулятор рідини LuV
+metaitem.fluid.regulator.uv.name=Регулятор рідини UV
+metaitem.conveyor.module.lv.name=Конвеєрний модуль LV
+metaitem.conveyor.module.mv.name=Конвеєрний модуль MV
+metaitem.conveyor.module.ev.name=Конвеєрний модуль EV
+metaitem.conveyor.module.zpm.name=Конвеєрний модуль ZPM
+metaitem.conveyor.module.uhv.name=Конвеєрний модуль UHV
+metaitem.conveyor.module.uiv.name=Конвеєрний модуль UIV
+metaitem.conveyor.module.uxv.name=Конвеєрний модуль UXV
+metaitem.conveyor.module.opv.name=Конвеєрний модуль OpV
+metaitem.electric.piston.lv.name=Електричний поршень LV
+metaitem.electric.piston.mv.name=Електричний поршень MV
+metaitem.electric.piston.ev.name=Електричний поршень EV
+metaitem.electric.piston.iv.name=Електричний поршень IV
+metaitem.electric.piston.luv.name=Електричний поршень LuV
+metaitem.electric.piston.zpm.name=Електричний поршень ZPM
+metaitem.electric.piston.uhv.name=Електричний поршень UHV
+metaitem.electric.piston.uev.name=Електричний поршень UEV
+metaitem.electric.piston.uiv.name=Електричний поршень UIV
+metaitem.electric.piston.uxv.name=Електричний поршень UXV
+metaitem.electric.piston.opv.name=Електричний поршень OpV
+metaitem.robot.arm.mv.name=Роботизована рука MV
+metaitem.robot.arm.hv.name=Роботизована рука HV
+metaitem.robot.arm.iv.name=Роботизована рука IV
+metaitem.robot.arm.luv.name=Роботизована рука LuV
+metaitem.robot.arm.uv.name=Роботизована рука UV
+metaitem.robot.arm.uhv.name=Роботизована рука UHV
+metaitem.robot.arm.uiv.name=Роботизована рука UIV
+metaitem.robot.arm.opv.name=Роботизована рука OpV
+metaitem.field.generator.mv.name=Генератор поля MV
+metaitem.field.generator.ev.name=Генератор поля EV
+metaitem.field.generator.iv.name=Генератор поля IV
+metaitem.field.generator.luv.name=Генератор поля LuV
+metaitem.field.generator.zpm.name=Генератор поля ZPM
+metaitem.field.generator.uhv.name=Генератор поля UHV
+metaitem.field.generator.uev.name=Генератор поля UEV
+metaitem.field.generator.uiv.name=Генератор поля UIV
+metaitem.emitter.mv.name=Випромінювач MV
+metaitem.emitter.ev.name=Випромінювач EV
+metaitem.emitter.iv.name=Випромінювач IV
+metaitem.emitter.luv.name=Випромінювач LuV
+metaitem.emitter.zpm.name=Випромінювач ZPM
+metaitem.emitter.uev.name=Випромінювач UEV
+metaitem.emitter.uxv.name=Випромінювач UXV
+metaitem.emitter.opv.name=Випромінювач OpV
+metaitem.sensor.lv.name=Сенсор LV
+metaitem.sensor.mv.name=Сенсор MV
+metaitem.sensor.ev.name=Сенсор EV
+metaitem.sensor.iv.name=Сенсор IV
+metaitem.sensor.luv.name=Сенсор LuV
+metaitem.sensor.zpm.name=Сенсор ZPM
+metaitem.sensor.uv.name=Сенсор UV
+metaitem.sensor.uhv.name=Сенсор UHV
+metaitem.sensor.uev.name=Сенсор UEV
+metaitem.sensor.uiv.name=Сенсор UIV
+metaitem.sensor.opv.name=Сенсор OpV
+metaitem.tool.datastick.name=Накопичувач даних
+metaitem.tool.datastick.tooltip=Сховище для простих даних
+metaitem.tool.dataorb.name=Сфера даних
+metaitem.tool.datamodule.name=Модуль даних
+metaitem.circuit.integrated.name=Запрограмована схема
+metaitem.circuit.integrated.tooltip=ПКМ щоб відкрити графічний інтерфейс/n/nShift-ПКМ по машині/nзі схемою в руці/nщоб запрограмувати машину./n
+metaitem.circuit.integrated.gui=Конфігурація схеми
+item.glass.lens=Скляна лінза (Біла)
+metaitem.glass_lens.orange.name=Скляна лінза (Помаранчева)
+metaitem.glass_lens.magenta.name=Скляна лінза (Пурпурна)
+metaitem.glass_lens.pink.name=Скляна лінза (Рожева)
+metaitem.glass_lens.yellow.name=Скляна лінза (Жовта)
+metaitem.glass_lens.light_gray.name=Скляна лінза (Світло-сіра)
+metaitem.glass_lens.cyan.name=Скляна лінза (Блакитна)
+metaitem.glass_lens.purple.name=Скляна лінза (Фіолетова)
+metaitem.glass_lens.green.name=Скляна лінза (Зелена)
+metaitem.glass_lens.red.name=Скляна лінза (Червона)
+metaitem.glass_lens.black.name=Скляна лінза (Чорна)
+
+#CIRCUITS LOCALIZATION
+metaitem.boule.silicon.name=Монокристалічний кремній
+metaitem.boule.phosphorus.tooltip=Необроблена схема
+metaitem.boule.naquadah.tooltip=Необроблена схема
+metaitem.boule.neutronium.tooltip=Необроблена схема
+metaitem.wafer.phosphorus.tooltip=Необроблена схема
+metaitem.board.epoxy.tooltip=Покращена плата
+metaitem.board.fiber_reinforced.tooltip=Екстремально гарна плата
+metaitem.board.multilayer.fiber_reinforced.name=Багато рівнева посилена волокном друкована плата
+metaitem.board.fiber_reinforced.name=Посилена волокном друкована плата
+metaitem.board.multilayer.fiber_reinforced.tooltip=Відмінна плата
+metaitem.board.wetware.name=Друкована плата зі системою життєзабезпечення
+metaitem.board.wetware.tooltip=Плата, яка зберігає життя
+metaitem.circuit_board.basic.name=Друкована плата
+metaitem.circuit_board.basic.tooltip=Базова друкована плата
+metaitem.circuit_board.good.name=Гарна друкована плата
+metaitem.circuit_board.good.tooltip=Гарна друкована плата
+metaitem.circuit_board.plastic.name=Пластикова друкована плата
+metaitem.circuit_board.plastic.tooltip=Гарна друкована плата
+metaitem.circuit_board.advanced.name=Покращена друкована плата
+metaitem.circuit_board.advanced.tooltip=Покращена друкована плата
+metaitem.circuit_board.extreme.name=Екстремально гарна друкована плата
+metaitem.circuit_board.extreme.tooltip=Більш покращена друкована плата
+metaitem.circuit_board.elite.tooltip=Відмінна друкована плата
+metaitem.circuit.vacuum_tube.name=Вакумна лампа
+metaitem.component.diode.name=Діод
+metaitem.component.diode.tooltip=Базовий електричний компонент
+metaitem.component.resistor.name=Резистор
+metaitem.component.resistor.tooltip=Базовий електричний компонент
+metaitem.component.transistor.name=Транзистор
+metaitem.component.capacitor.name=Конденсатор
+metaitem.component.glass.tube.name=Скляна трубка
+metaitem.component.inductor.name=Індуктор
+metaitem.component.inductor.tooltip=Мала котушка
+metaitem.component.smd.diode.name=SMD Діод
+metaitem.component.smd.capacitor.name=SMD Конденсатор
+metaitem.component.smd.capacitor.tooltip=Електричний компонент
+metaitem.component.smd.transistor.tooltip=Електричний компонент
+metaitem.component.smd.resistor.name=SMD Резистор
+metaitem.component.smd.resistor.tooltip=Електричний компонент
+metaitem.component.smd.inductor.name=SMD Індуктор
+metaitem.component.smd.inductor.tooltip=Електричний компонент
+metaitem.component.advanced_smd.diode.name=Покращений SMD Діод
+metaitem.component.advanced_smd.capacitor.name=Покращений SMD Конденсатор
+metaitem.component.advanced_smd.capacitor.tooltip=Покращений електричний компонент
+metaitem.component.advanced_smd.transistor.name=Покращений SMD Транзистор
+metaitem.component.advanced_smd.resistor.name=Покращений SMD Резистор
+metaitem.component.advanced_smd.resistor.tooltip=Покращений електричний компонент
+metaitem.component.advanced_smd.inductor.name=Покращений SMD Індуктор
+metaitem.component.advanced_smd.inductor.tooltip=Покращений електричний компонент
+metaitem.wafer.advanced_system_on_chip.name=Пластина ASoC
+metaitem.wafer.advanced_system_on_chip.tooltip=Необроблена покращена схема
+metaitem.wafer.central_processing_unit.tooltip=Необроблений модуль обробки
+metaitem.credit.cupronickel.name=Купронікелевий кредит
+metaitem.credit.cupronickel.tooltip=1 Кредит
+metaitem.electric.discharge_mode.tooltip=Використовуйте затиснувши кнопку Присісти для перемикання режиму розрядки
+metaitem.crushed.tooltip.purify=Киньте в казан, щоб отримати очищену руду
+metaitem.shape.extruder.rotor.name=Форма екструдера (Ротор)
+metaitem.shape.extruder.rotor.tooltip=Форма екструдера для виготовлення роторів
+metaitem.credit.copper.name=Мідний кредит
+gregtech.multiblock.primitive_water_pump.extra1=Коефіцієнт біома:/n Океан, річка: 1000 л/с/n Болото: 800 л/с/n Джунглі: 350 л/с/n Засніжені: 300 л/с/n Рівнина, ліс: 250 л/с/n Тайга: 175 л/с/n Пляж: 170 Л/с/n Інше: 100 л/с
+gregtech.multiblock.advanced_processing_array.description=Оброблювальний масив об'єднує до 64 одноблочних машин в один мультиблок, що значно полегшує автоматизацію.
+gregtech.tooltip.fluid_pipe_hold_shift=Утримуйте SHIFT, щоб відобразити інформацію про рідину
+metaitem.electric.discharge_mode.disabled=§eВимкнено режим розряду
+metaitem.shape.extruder.bottle.tooltip=Форма екструдера для виготовлення пляшок
+metaitem.shape.extruder.gear_small.tooltip=Форма екструдера для виготовлення малих шестерень
+metaitem.shape.extruder.foil.name=Форма екструдера (Фольга)
+metaitem.shape.extruder.gear_small.name=Форма екструдера (Мала шестерня)
+metaitem.shape.extruder.foil.tooltip=Форма екструдера для виготовлення фольги з неметалів
+metaitem.plant.ball.name=Кулька біомаси
+metaitem.fluid_cell.universal.empty=Порожньо
+metaitem.large_fluid_cell.aluminium.name=%s Алюмінієва капсула
+metaitem.large_fluid_cell.stainless_steel.name=%s Капсула з нержавіючої сталі
+metaitem.large_fluid_cell.tungstensteel.name=%s Вольфрамова капсула
+metaitem.spray.can.dyes.white.name=Балончик (білий)
+metaitem.spray.can.dyes.magenta.name=Балончик (пурпурний)
+metaitem.spray.can.dyes.yellow.name=Балончик (жовтий)
+metaitem.spray.can.dyes.lime.name=Балончик (лайм)
+metaitem.spray.can.dyes.pink.name=Балончик (рожевий)
+metaitem.spray.can.dyes.gray.name=Балончик (сірий)
+metaitem.spray.can.dyes.silver.name=Балончик (світло-сірий)
+metaitem.spray.can.dyes.cyan.name=Балончик (блакитний)
+metaitem.spray.can.dyes.blue.name=Балончик (синій)
+metaitem.spray.can.dyes.brown.name=Балончик (коричневий)
+metaitem.spray.can.dyes.green.name=Балончик (зелений)
+metaitem.spray.can.dyes.red.name=Балончик (червоний)
+metaitem.spray.can.dyes.black.name=Балончик (чорний)
+metaitem.tool.matchbox.name=Сірникова коробка
+metaitem.tool.matchbox.tooltip=Це не автомобіль
+metaitem.tool.lighter.platinum.tooltip=На ньому викарбувано відомого майстра жартів
+metaitem.battery.hull.lv.tooltip=Порожній §7LV §7корпус батареї
+metaitem.battery.hull.mv.tooltip=Порожній §bMV §7корпус батареї
+metaitem.tool.lighter.invar.name=Запальничка
+
+
+metaitem.battery.hull.lv.name=Малий корпус батареї
+metaitem.battery.hull.mv.name=Середній корпус батареї
+metaitem.battery.hull.hv.tooltip=Великий §6HV §7корпус батареї
+metaitem.battery.hull.iv.name=Корпус середньої ванадієвої батареї
+metaitem.battery.hull.iv.tooltip=Порожній §1IV §7корпус батареї
+metaitem.battery.re.ulv.tantalum.tooltip=Багаторазова батарея
+metaitem.battery.re.lv.sodium.tooltip=Багаторазова батарея
+metaitem.battery.re.mv.cadmium.name=Середня кадмієва батарея
+metaitem.battery.re.hv.lithium.tooltip=Багаторазова батарея
+metaitem.battery.re.hv.sodium.tooltip=Багаторазова батарея
+metaitem.battery.ev.vanadium.tooltip=Багаторазова батарея
+metaitem.battery.iv.vanadium.tooltip=Багаторазова батарея
+metaitem.battery.zpm.naquadria.name=Середня наквадрієва батарея
+metaitem.battery.zpm.naquadria.tooltip=Багаторазова батарея
+metaitem.battery.hull.ev.tooltip=Порожній §5EV §7корпус батареї
+metaitem.battery.hull.luv.name=Великий ванадієвий корпус батареї
+metaitem.battery.hull.luv.tooltip=Порожній §dLuV §7корпус батареї
+metaitem.battery.charge_unit.second=сек
+metaitem.battery.re.lv.lithium.tooltip=Багаторазова батарея
+metaitem.battery.re.lv.sodium.name=Маленька натрієва батарея
+metaitem.battery.re.mv.lithium.name=Середня літієва батарея
+metaitem.battery.re.mv.lithium.tooltip=Багаторазова батарея
+metaitem.battery.re.mv.sodium.name=Середня натрієва батарея
+metaitem.battery.uv.naquadria.tooltip=Багаторазова батарея
+metaitem.energy_crystal.tooltip=Багаторазова батарея
+metaitem.lapotron_crystal.name=Лапотроний кристал
+metaitem.lapotron_crystal.tooltip=Багаторазова батарея
+metaitem.energy.lapotronic_orb_cluster.tooltip=Багаторазова батарея
+metaitem.zpm.name=Модуль нульової точки
+metaitem.energy.cluster.tooltip=Багаторазова батарея
+metaitem.max.battery.name=Досконала батарея
+metaitem.electric.motor.iv.name=Електродвигун IV
+metaitem.energy.lapotronic_orb.name=Лапотронічна енергетична куля
+metaitem.energy.module.tooltip=Багаторазова батарея
+metaitem.fluid.regulator.tooltip=Обмежує §fРідини§7 до певної кількості, працює як §fПокращення§7.
+metaitem.electric.pump.tooltip=Переводить §fРідини§7 з одинаковою швидкістю, працює як §fПокращення§7.
+metaitem.electric.motor.lv.name=Електродвигун LV
+metaitem.electric.motor.mv.name=Електродвигун MV
+metaitem.electric.motor.hv.name=Електродвигун HV
+metaitem.electric.motor.ev.name=Електродвигун EV
+metaitem.electric.motor.uhv.name=Електродвигун UHV
+metaitem.electric.motor.uiv.name=Електродвигун UIV
+metaitem.electric.motor.opv.name=Електродвигун OpV
+metaitem.electric.pump.lv.name=Електронасос LV
+metaitem.electric.pump.hv.name=Електронасос HV
+metaitem.electric.pump.uhv.name=Електронасос UHV
+metaitem.fluid.regulator.hv.name=Регулятор рідини HV
+metaitem.fluid.regulator.ev.name=Регулятор рідини EV
+metaitem.conveyor.module.hv.name=Конвеєрний модуль HV
+metaitem.conveyor.module.iv.name=Конвеєрний модуль IV
+metaitem.conveyor.module.uev.name=Конвеєрний модуль UEV
+metaitem.conveyor.module.tooltip=Передає §fПредмети§7 з одинаковою швидкістю, працює як §fПокращення§7.
+metaitem.electric.piston.hv.name=Електричний поршень HV
+metaitem.electric.piston.uv.name=Електричний поршень UV
+metaitem.robot.arm.uxv.name=Роботизована рука UXV
+metaitem.field.generator.lv.name=Генератор поля LV
+metaitem.field.generator.uxv.name=Генератор поля UXV
+metaitem.emitter.lv.name=Випромінювач LV
+metaitem.electric.motor.uv.name=Електродвигун UV
+metaitem.electric.pump.mv.name=Електронасос MV
+metaitem.electric.pump.luv.name=Електронасос LuV
+metaitem.electric.pump.zpm.name=Електронасос ZPM
+metaitem.electric.pump.uv.name=Електронасос UV
+metaitem.electric.pump.uiv.name=Електронасос UIV
+metaitem.electric.pump.opv.name=Електронасос OpV
+metaitem.fluid.regulator.iv.name=Регулятор рідини IV
+metaitem.fluid.regulator.zpm.name=Регулятор рідини ZPM
+metaitem.conveyor.module.luv.name=Конвеєрний модуль LuV
+metaitem.conveyor.module.uv.name=Конвеєрний модуль UV
+metaitem.robot.arm.lv.name=Роботизована рука LV
+metaitem.robot.arm.ev.name=Роботизована рука EV
+metaitem.robot.arm.zpm.name=Роботизована рука ZPM
+metaitem.robot.arm.uev.name=Роботизована рука UEV
+metaitem.robot.arm.tooltip=Обмежує §fПредмети§7 до певної кількості, працює як §fПокращення§7.
+metaitem.field.generator.hv.name=Генератор поля HV
+metaitem.field.generator.uv.name=Генератор поля UV
+metaitem.field.generator.opv.name=Генератор поля OpV
+metaitem.emitter.hv.name=Випромінювач HV
+metaitem.emitter.uv.name=Випромінювач UV
+metaitem.emitter.uiv.name=Випромінювач UIV
+metaitem.tool.dataorb.tooltip=Сховище для складних даних
+metaitem.tool.datamodule.tooltip=Сховище для неймовірно складних даних/n§cМоже бути прочитане лише банком даних
+metaitem.emitter.uhv.name=Випромінювач UHV
+metaitem.sensor.hv.name=Сенсор HV
+metaitem.sensor.uxv.name=Сенсор UXV
+metaitem.board.epoxy.name=Епоксидна друкована плата
+metaitem.glass_lens.light_blue.name=Скляна лінза (Світло-блакитна)
+metaitem.circuit.integrated.jei_description=JEI показує рецепти тільки для даної конфігурації.\n\nВи можете вибрати конфігурацію у графічному інтерфейсі схеми.
+metaitem.spray.can.dyes.light_blue.name=Балончик (світло-синій)
+metaitem.glass_lens.blue.name=Скляна лінза (Синя)
+metaitem.boule.silicon.tooltip=Необроблена схема
+metaitem.wafer.silicon.tooltip=Необроблена схема
+metaitem.wafer.phosphorus.name=Пластина легована фосфором
+metaitem.wafer.naquadah.name=Пластина легована наквадою
+metaitem.boule.naquadah.name=Монокристалічний кремній легований наквадою
+metaitem.board.plastic.name=Пластмасова друкована плата
+metaitem.circuit_board.elite.name=Відмінна друкована плата
+metaitem.circuit_board.wetware.tooltip=Плата, яка зберігає життя
+metaitem.circuit.vacuum_tube.tooltip=Технічно це діод/n рівень §cULV
+metaitem.component.transistor.tooltip=Базовий електричний компонент
+metaitem.glass_lens.lime.name=Glass Lens (Лаймова)
+metaitem.glass_lens.gray.name=Скляна лінза (Сіра)
+metaitem.glass_lens.brown.name=Скляна лінза (Коричнева)
+metaitem.boule.phosphorus.name=Монокристалічний кремній легований фосфором
+metaitem.wafer.silicon.name=Кремнієва Пластина
+metaitem.wafer.naquadah.tooltip=Необроблена схема
+metaitem.wafer.neutronium.name=Пластина легована нейтронами
+metaitem.boule.neutronium.name=Монокристалічний кремній легований нейтронами
+metaitem.wafer.neutronium.tooltip=Необроблена схема
+metaitem.board.coated.name=Друкована плата з покриттям
+metaitem.board.coated.tooltip=Плата з покриттям
+metaitem.board.phenolic.name=Фенольна друкована плата
+metaitem.board.phenolic.tooltip=Гарна плата
+metaitem.board.plastic.tooltip=Гарна плата
+metaitem.component.capacitor.tooltip=Базовий електричний компонент
+metaitem.component.smd.diode.tooltip=Електричний компонент
+metaitem.component.smd.transistor.name=SMD Транзистор
+metaitem.component.advanced_smd.diode.tooltip=Покращений електричний компонент
+metaitem.component.advanced_smd.transistor.tooltip=Покращений електричний компонент
+metaitem.wafer.highly_advanced_system_on_chip.tooltip=Необроблена високотехнологічна схема
+metaitem.wafer.high_power_integrated_circuit.tooltip=Необроблена схема високої потужності
+metaitem.wafer.central_processing_unit.name=Процесорна пластина
+metaitem.petri_dish.name=Чашка Петрі
+metaitem.duct_tape.name=Покращена армована клейка стрічка FAL-84
+metaitem.basic_tape.tooltip=Недостатньо міцна для вирішення механічних проблем
+metaitem.gravistar.tooltip=Доскональна пекельна зірка
+metaitem.carbon.mesh.name=Сітка з вуглецевого волокна
+metaitem.carbon.plate.name=Вуглецева пластина
+metaitem.minecart_wheels.steel.tooltip=Щоб все їхало за планом
+metaitem.wafer.ultra_high_power_integrated_circuit.name=Пластина UHPIC
+metaitem.wafer.ultra_high_power_integrated_circuit.tooltip=Необроблена схема надвисокої напруги
+metaitem.wafer.nand_memory_chip.name=Пластина NAND
+metaitem.wafer.nand_memory_chip.tooltip=Необроблений логічний вентиль
+metaitem.wafer.ultra_low_power_integrated_circuit.name=Пластина ULPIC
+metaitem.wafer.ultra_low_power_integrated_circuit.tooltip=Необроблена схема наднизької напруги
+metaitem.wafer.low_power_integrated_circuit.name=Пластина LPIC
+metaitem.wafer.low_power_integrated_circuit.tooltip=Необроблена схема низької напруги
+metaitem.wafer.power_integrated_circuit.name=Пластина PIC
+metaitem.wafer.power_integrated_circuit.tooltip=Необлена схема напруги
+metaitem.wafer.nano_central_processing_unit.name=Пластина нанопроцесора
+metaitem.wafer.nor_memory_chip.name=Пластина NOR
+metaitem.wafer.nor_memory_chip.tooltip=Необроблений логічний вентиль
+metaitem.wafer.random_access_memory.name=Пластина RAM
+metaitem.wafer.random_access_memory.tooltip=Необроблена пам'ять
+metaitem.wafer.system_on_chip.name=Пластина SoC
+metaitem.wafer.simple_system_on_chip.name=Проста пластина SoC
+metaitem.wafer.simple_system_on_chip.tooltip=Необроблена проста схема
+metaitem.engraved.crystal_chip.name=Гравірований кришталевий чіп
+metaitem.engraved.crystal_chip.tooltip=Потрібен для схем
+metaitem.crystal.raw.name=Необроблений кришталевий чіп
+metaitem.crystal.raw_chip.name=Частини необробленого криштального чіпа
+metaitem.engraved.lapotron_chip.name=Гравірований лапотроний криштальний чіп
+metaitem.crystal.central_processing_unit.name=Криштальний CPU
+metaitem.crystal.central_processing_unit.tooltip=Криштальний модуль обробки
+metaitem.crystal.system_on_chip.name=Криштальний SoC
+metaitem.crystal.system_on_chip.tooltip=Криштальна система на чіпі
+metaitem.plate.advanced_system_on_chip.name=ПСнЧ
+metaitem.plate.highly_advanced_system_on_chip.name=ВТСнЧ
+metaitem.plate.highly_advanced_system_on_chip.tooltip=Високотехнологічна система на чіпі
+metaitem.plate.integrated_logic_circuit.name=Вбудована схема
+metaitem.plate.integrated_logic_circuit.tooltip=Вбудована логічна схема
+metaitem.plate.central_processing_unit.name=ЦП
+metaitem.plate.central_processing_unit.tooltip=Центральний процесор
+metaitem.plate.high_power_integrated_circuit.name=ВСВН
+metaitem.plate.high_power_integrated_circuit.tooltip=Вбудована схема високої напруги
+metaitem.plate.ultra_high_power_integrated_circuit.tooltip=Вбудована схема надвисокої напруги
+metaitem.plate.ultra_high_power_integrated_circuit.name=ВСНВН
+metaitem.plate.nand_memory_chip.name=NAND
+metaitem.plate.nand_memory_chip.tooltip=Логічний вентиль NAND
+metaitem.plate.nano_central_processing_unit.name=Нано ЦП
+metaitem.plate.nano_central_processing_unit.tooltip=Нанопроцесор
+metaitem.plate.nor_memory_chip.name=NOR
+metaitem.plate.nor_memory_chip.tooltip=Логічний вентиль NOR
+metaitem.circuit.good_electronic.name=Гарна електрична схема
+metaitem.circuit.good_electronic.tooltip=Твоя друга схема/n§cРівень MV
+metaitem.plate.ultra_low_power_integrated_circuit.tooltip=Вбудована схема наднизької напруги
+metaitem.plate.low_power_integrated_circuit.name=ВСНН
+metaitem.plate.ultra_low_power_integrated_circuit.name=ВСННН
+metaitem.plate.low_power_integrated_circuit.tooltip=Вбудована схема низької напруги
+metaitem.plate.power_integrated_circuit.name=ВСН
+metaitem.plate.power_integrated_circuit.tooltip=Вбудована схема напруги
+metaitem.plate.random_access_memory.name=RAM
+metaitem.plate.random_access_memory.tooltip=Пам'ять з довільним доступом
+metaitem.plate.system_on_chip.name=СнЧ
+metaitem.plate.system_on_chip.tooltip=Система на чіпі
+metaitem.plate.simple_system_on_chip.name=Проста СнЧ
+metaitem.plate.simple_system_on_chip.tooltip=Проста система на чіпі
+
+
+# T1: Electronic
+metaitem.circuit.electronic.name=Проста електрична схема
+metaitem.circuit.electronic.tooltip=Твоя перша схема/n§cРівень LV
+
+# T2: Integrated
+metaitem.circuit.basic_integrated.name=Вбудована логічна схема
+metaitem.circuit.basic_integrated.tooltip=Менша та більш потужна/n§6Рівень LV
+metaitem.circuit.good_integrated.name=Гарна вбудована схема
+metaitem.circuit.good_integrated.tooltip=Менша та більш потужна/n§6Рівень MV
+metaitem.circuit.advanced_integrated.name=Покращена вбудована схема
+metaitem.circuit.advanced_integrated.tooltip=Менша та більш потужна/n§6Рівень HV
+
+# Misc
+metaitem.circuit.nand_chip.name=Чіп NAND
+metaitem.circuit.nand_chip.tooltip=Передова проста схема/n§6Рівень ULV
+metaitem.circuit.microprocessor.name=Мікропроцесор
+metaitem.circuit.microprocessor.tooltip=Передова базова схема/n§eРівень LV
+
+# T3: Processor
+metaitem.circuit.processor.name=Вбудований процесор
+metaitem.circuit.processor.tooltip=Дивовижна швидкість обчислення!/n§eРівень MV
+metaitem.circuit.assembly.name=Обчислювальний процесор
+metaitem.circuit.assembly.tooltip=Дивовижна швидкість обчислення!/n§eРівень HV
+metaitem.circuit.workstation.name=Суперкомп'ютер
+metaitem.circuit.workstation.tooltip=Дивовижна швидкість обчислення!/n§eРівень EV
+metaitem.circuit.mainframe.name=Основний каркас
+metaitem.circuit.mainframe.tooltip=Дивовижна швидкість обчислення!/n§eРівень IV
+
+# T4: Nano
+metaitem.circuit.nano_processor.name=Нанопроцесор
+metaitem.circuit.nano_processor.tooltip=Менше, ніж будь-коли/n§bРівень HV
+metaitem.circuit.nano_assembly.name=Обчислювальний нанопроцесор
+metaitem.circuit.nano_assembly.tooltip=Менше, ніж будь-коли/n§bРівень EV
+metaitem.circuit.nano_computer.name=Наносуперкомп'ютер
+metaitem.circuit.nano_computer.tooltip=Менше, ніж будь-коли/n§bРівень IV
+metaitem.circuit.nano_mainframe.name=Основний каркас нанопроцесора
+metaitem.circuit.nano_mainframe.tooltip=Менше, ніж будь-коли/n§bРівень LuV
+
+# T5: Quantum
+metaitem.circuit.quantum_processor.name=Квантовий процесор
+metaitem.circuit.quantum_processor.tooltip=Квантові обчислення втілюються в життя!/n§aРівень EV
+metaitem.circuit.quantum_assembly.name=Обчислювальний квантовий процесор
+metaitem.circuit.quantum_assembly.tooltip=Квантові обчислення втілюються в життя!/n§aРівень IV
+metaitem.circuit.quantum_computer.name=Квантовий суперкомп'ютер
+metaitem.circuit.quantum_computer.tooltip=Квантові обчислення втілюються в життя!/n§aРівень LuV
+metaitem.circuit.quantum_mainframe.name=Основний каркас квантового процесора
+metaitem.circuit.quantum_mainframe.tooltip=Квантові обчислення втілюються в життя!/n§aРівень ZPM
+
+# T6: Crystal
+metaitem.circuit.crystal_processor.name=Криштальний процесор
+metaitem.circuit.crystal_processor.tooltip=Використання переваг гравіювання на кришталі/n§9Рівень IV
+metaitem.circuit.crystal_assembly.name=Обчислювальний криштальний процесор
+metaitem.circuit.crystal_assembly.tooltip=Використання переваг гравіювання на кришталі/n§9Рівень LuV
+metaitem.circuit.crystal_computer.name=Криштальний суперкомп'ютер
+metaitem.circuit.crystal_computer.tooltip=Використання переваг гравіювання на кришталі/n§9Рівень ZPM
+metaitem.circuit.crystal_mainframe.name=Основний каркас криштального процесора
+metaitem.circuit.crystal_mainframe.tooltip=Використання переваг гравіювання на кришталі/n§9Рівень UV
+
+# T7: Wetware
+metaitem.circuit.wetware_processor.name=Органічний процесор
+metaitem.circuit.wetware_processor.tooltip=У тебе таке відчуття, ніби воно спостерігає за тобою./n§4РівеньLuV
+metaitem.circuit.wetware_assembly.name=Обчислювальний органічний процесор
+metaitem.circuit.wetware_assembly.tooltip=Зможе запустити Minecraft/n§4Рівень ZPM
+metaitem.circuit.wetware_computer.name=Органічний суперкомп'ютер
+metaitem.circuit.wetware_mainframe.name=Основний каркас органічного процесора
+metaitem.circuit.wetware_computer.tooltip=Ідеальне поєднання плоті та машини/n§4Рівень UV
+metaitem.circuit.wetware_mainframe.tooltip=Потужне, але чи сможе воно запустити Crysis?/n§4Рівень UHV
+metaitem.stem_cells.name=Cтовбурові клітини
+metaitem.stem_cells.tooltip=Сирий інтелект
+metaitem.processor.neuro.name=Нейроний модуль обробки
+metaitem.processor.neuro.tooltip=Нейроний процесор
+metaitem.petri_dish.tooltip=Для вирощування клітин
+metaitem.bio_chaff.name=Біологічна маса
+metaitem.carbon.fibers.name=Сире вуглецеве волокно
+metaitem.neutron_reflector.name=Іридієвий нейтронний відбивач
+metaitem.neutron_reflector.tooltip=Незламний
+metaitem.duct_tape.tooltip=Якщо ви не можете виправити це за допомогою цього, використайте більше!
+metaitem.basic_tape.name=Стрічка
+metaitem.component.grinder.diamond.name=Алмазна шліфувальна головка
+metaitem.component.grinder.tungsten.name=Вольфрамова шліфувальна головка
+metaitem.minecart_wheels.iron.name=Залізні колеса вагонетки
+metaitem.minecart_wheels.iron.tooltip=Щоб все їхало за планом
+metaitem.minecart_wheels.steel.name=Стальні колеса вагонетки
+metaitem.quantumeye.name=Квантове око
+metaitem.quantumeye.tooltip=Вдосконалене око енду
+metaitem.quantumstar.name=Квантова зірка
+metaitem.quantumstar.tooltip=Вдосконалена пекельна зірка
+metaitem.gravistar.name=Гравітаційна зірка
+metaitem.item_filter.name=Фільтр предметів
+metaitem.wafer.system_on_chip.tooltip=Необроблена базова схема
+metaitem.wafer.nano_central_processing_unit.tooltip=Необроблема наносхема
+metaitem.crystal.raw_chip.tooltip=Частини необробленого криштального процесора
+metaitem.plate.advanced_system_on_chip.tooltip=Покращена система на чіпі
+metaitem.crystal.raw.tooltip=Необроблений кришталевий процесор
+metaitem.fluid_filter.name=Фільтр рідини
+metaitem.ore_dictionary_filter.name=Фільтр руди
+metaitem.fluid_filter.tooltip=Фільтрує §fРідини§7 працює як §fПокращення§7./nМожна виковистовувати для покращення §fЕлектронасоса§7 і §fРегулятора рідини§7.
+metaitem.smart_item_filter.name=Розумний фільтр предметів
+behaviour.filter_ui_manager=§fПКМ§7 для налаштувань, §fShift ПКМ§7 для очищення налаштувань
+metaitem.cover.controller.name=Контролер машини
+metaitem.cover.activity.detector.tooltip=Видає §fСтатус роботи§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.fluid.detector.tooltip=Видає §fКількість рідини§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.item.detector.tooltip=Видає §fКількість предметів§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.activity.detector.name=Датчик активності
+metaitem.cover.fluid.detector.name=Датчик рідини
+metaitem.cover.fluid.detector.advanced.name=Покращений датчик рідини
+metaitem.cover.item.detector.name=Датчик предметів
+metaitem.cover.item.detector.advanced.name=Покращений датчик предметів
+metaitem.cover.fluid.voiding.name=Видалятор рідини
+metaitem.cover.fluid.voiding.tooltip=Видаляє §fРідини§7, працює як §fПокращення§7./nАктивується за допомогою §fМ'якої киянки§7 після розміщення.
+metaitem.cover.fluid.voiding.advanced.name=Покращення видалятор рідини
+metaitem.cover.item.voiding.name=Видалятор предметів
+metaitem.cover.item.voiding.tooltip=Видаляє §fПредмети§7 працює як §fПокращення§7./nАктивується за допомогою §fМ'якої киянки§7 після розміщення.
+metaitem.cover.item.voiding.advanced.name=Покращений видалятор предметів
+metaitem.cover.storage.name=Сховище (Покращення)
+metaitem.cover.energy.detector.advanced.name=Покращений датчик енергії
+metaitem.cover.maintenance.detector.tooltip=Видає §fПотребу в технічного обслуговування§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.facade.name=Фасад (%s)
+metaitem.cover.screen.name=Комп'ютерний монітор
+metaitem.cover.screen.tooltip=Показує §fДані§7, працює як §fПокращення§7.
+metaitem.cover.crafting.name=Верстак (Покращення)
+metaitem.cover.shutter.name=Затворний модуль (Покращення)
+metaitem.cover.shutter.tooltip=§fБлокує передачу§7 через сторону на якій знаходиться, працює як §fПокращення§7.
+metaitem.cover.solar.panel.ulv.name=Сонячна панель ультранизької напруги
+metaitem.cover.solar.panel.mv.name=Сонячна панель середньої напруги (Покращення)
+metaitem.cover.solar.panel.hv.name=Сонячна панель високої напруги (Покращення)
+metaitem.cover.solar.panel.iv.name=Сонячна панель шаленої напруги (Покращення)
+metaitem.cover.solar.panel.luv.name=Сонячна панель сміховинної напруги (Покращення)
+metaitem.cover.solar.panel.uv.name=Сонячна панель кінцевої напруги (Покращення)
+metaitem.cover.solar.panel.tooltip.1=Нехай Сонце буде з вами.
+metaitem.cover.infinite_water.name=Нескінченне джерело води (Покращення)
+metaitem.cover.infinite_water.tooltip.1=Наповнює контейнери §9Водою§7, працює як §fПокращення§7.
+metaitem.cover.ender_fluid_link.name=Рідкий безтрубний зв'язок (Покращення)
+metaitem.gelled_toluene.tooltip=Сира вибухівка
+metaitem.bottle.purple.drink.name=Фіолетовий напій
+metaitem.bottle.purple.drink.tooltip=Як щодо лимонаду? Або холодного чаю? А у мене є фіолетовий напій!
+metaitem.dye.black.name=Чорний барвник
+metaitem.dye.red.name=Червоний барвник
+metaitem.dye.green.name=Зелений барвник
+metaitem.dye.blue.name=Синій барвник
+metaitem.dye.purple.name=Фіолетовий барвник
+metaitem.dye.cyan.name=Блакитний барвник
+metaitem.dye.silver.name=Світло-сірий барвник
+metaitem.dye.gray.name=Сірий барвник
+metaitem.dye.lime.name=Лаймовий барвник
+metaitem.dye.magenta.name=Пурпурний барвник
+metaitem.dye.orange.name=Помаранчевий барвник
+metaitem.dye.white.name=Білий барвник
+metaitem.tool_parts_box.name=Ящик для інструментів
+metaitem.foam_sprayer.name=Розпилювач піни
+metaitem.energium_dust.name=Енергітичний пил
+metaitem.compressed.clay.name=Спресована глина
+metaitem.compressed.fireclay.name=Спресована шамотна глина
+metaitem.brick.fireclay.name=Цегла з шамотної глина
+metaitem.brick.fireclay.tooltip=Термостійка
+metaitem.brick.coke.name=Цегла для коксових печей
+metaitem.wooden_form.empty.name=Порожня дерев'яна форма
+item.gt.tool.replace_tool_head=Створіть нову головку інструменту, щоб замінити її
+item.gt.tool.usable_as=Використовується як: §f%s
+item.gt.tool.behavior.tree_felling=§4Лісоруб: §fРубка дерев
+item.gt.tool.behavior.shield_disable=§cБрут: §fВідключає щити
+item.gt.tool.behavior.ground_tilling=§eФермер: §fОбробляє землю
+item.gt.tool.behavior.rail_rotation=§eЗалізничний інженер: §fОбертає рейки
+item.gt.tool.behavior.block_rotation=§2Механік: §fОбертає блоки
+gt.tool.class.sword=Меч
+gt.tool.class.pickaxe=Кайло
+gt.tool.class.shovel=Лопата
+gt.tool.class.axe=Сокира
+gt.tool.class.hoe=Мотика
+gt.tool.class.saw=Пила
+gt.tool.class.hammer=Молот
+gt.tool.class.mallet=Киянка
+gt.tool.class.wrench=Гайковий ключ
+gt.tool.class.file=Напилок
+gt.tool.class.crowbar=Лом
+gt.tool.class.screwdriver=Викрутка
+gt.tool.class.mortar=Ступка
+gt.tool.class.scythe=Коса
+gt.tool.class.shears=Ножиці
+gt.tool.class.knife=Ніж
+gt.tool.class.plunger=Вантуз
+item.gt.tool.sword.name=Меч (%s)
+item.gt.tool.pickaxe.name=Кайло (%s)
+item.gt.tool.shovel.name=Лопата (%s)
+item.gt.tool.axe.name=Сокира (%s)
+item.gt.tool.hoe.name=Мотика (%s)
+item.gt.tool.saw.name=Пила (%s)
+item.gt.tool.hammer.name=Молот (%s)
+item.gt.tool.mallet.name=М'яка киянка (%s)
+item.gt.tool.mallet.tooltip=§8Зупиняє/запускає техніку
+item.gt.tool.wrench.name=Гайковий ключ %s
+item.gt.tool.file.name=Напилок (%s)
+item.gt.tool.crowbar.name=Лом (%s)
+item.gt.tool.crowbar.tooltip=§8Знімає покращення
+item.gt.tool.screwdriver.name=Викрутка (%s)
+item.gt.tool.screwdriver.tooltip=§8Налаштовує покращення та машини
+item.gt.tool.mortar.name=Ступка (%s)
+item.gt.tool.wire_cutter.name=Кусачки (%s)
+item.gt.tool.butchery_knife.name=Тесак (%s)
+item.gt.tool.butchery_knife.tooltip=§8Має низьку швидкість атаки
+item.gt.tool.scythe.name=Коса (%s)
+item.gt.tool.rolling_pin.name=Качалка (%s)
+item.gt.tool.drill_lv.name=%s Бур (LV)
+item.gt.tool.drill_hv.name=%s Бур (HV)
+item.gt.tool.drill_ev.name=%s Бур (EV)
+item.gt.tool.drill_iv.name=%s Бур (IV)
+item.gt.tool.mining_hammer.name=%s Гірський молот
+item.gt.tool.spade.tooltip=§8Видобуває велику площу за один раз (якщо тільки ви не присідаєте)
+item.gt.tool.chainsaw_lv.name=%s Бензопила (LV)
+item.gt.tool.chainsaw_mv.name=%s Бензопила (MV)
+item.gt.tool.chainsaw_hv.name=%s Бензопила (HV)
+item.gt.tool.wrench_lv.tooltip=§8Утримуйте ЛКМ, щоб демонтувати машини
+item.gt.tool.wrench_iv.tooltip=§8Утримуйте ЛКМ, щоб демонтувати машини
+item.gt.tool.buzzsaw.name=%s Циркулярна пила (LV)
+item.gt.tool.screwdriver_lv.name=%s Викрутка (LV)
+item.gt.tool.screwdriver_lv.tooltip=§8Налаштовує покращення та машини
+item.gt.tool.plunger.name=%s Вантуз
+item.gt.tool.plunger.tooltip=§8Видаляє рідини з машин
+item.gt.tool.wire_cutter_lv.name=%s Кусачки (LV)
+item.gt.tool.wire_cutter_hv.name=%s Кусачки (HV)
+item.gt.tool.tooltip.general_uses=§bМіцність: %s
+item.gt.tool.tooltip.attack_damage=§cШкода від атаки: %s
+item.gt.tool.tooltip.attack_speed=§9Швидкість атаки: %s
+item.gt.tool.tooltip.mining_speed=§dШвидкість видобутку: %s
+item.gt.tool.tooltip.harvest_level_extra=§eРівень збору: %s §f(%s§f)
+item.gt.tool.harvest_level.0=§8Дерево
+item.gt.tool.harvest_level.2=§aЗалізо
+item.gt.tool.harvest_level.3=§bАлмаз
+item.gt.tool.harvest_level.4=§dУльтімет
+item.gt.tool.harvest_level.5=§9Дюранієвий
+item.gt.tool.harvest_level.6=§cНейтроній
+item.gt.tool.tooltip.repair_info=Утримуйте клавішу SHIFT, щоб показати інформацію про ремонт
+item.gt.tool.tooltip.repair_material=Ремонтується з допомогою: §a%s
+item.gt.tool.aoe.rows=Ряди
+item.gt.tool.aoe.columns=Колонки
+item.gt.tool.aoe.layers=Шари
+metaitem.turbine_rotor.name=%s Ротор турбіни
+metaitem.turbine_rotor.tooltip=Ротори турбін для вашої електростанції
+metaitem.clipboard.name=Блокнот
+metaitem.clipboard.tooltip=Можна писати (без будь-якого інструменту для письма). Клацніть ПКМ на стіні, щоб розмістити, і клацніть Shift-ПКМ, щоб підібрати
+
+
+metaitem.behavior.mode_switch.tooltip=SHIFT-ПКМ для змінення режиму
+metaitem.behavior.mode_switch.mode_switched=§eРежим змінено на: %s
+metaitem.behavior.mode_switch.current_mode=Режим: %s
+metaitem.tool.tooltip.primary_material=§fМатеріал: §e%s
+metaitem.tool.tooltip.durability=§fМіцність: §a%,d / %,d
+metaitem.tool.tooltip.rotor.efficiency=Ефективність турбіни: §9%,d%%
+metaitem.tool.tooltip.rotor.power=Потужність турбіни: §9%,d%%
+metaitem.voltage_coil.ulv.name=Котушка (ULV)
+metaitem.voltage_coil.ulv.tooltip=Примітивна котушка
+metaitem.voltage_coil.lv.name=Котушка (LV)
+metaitem.voltage_coil.lv.tooltip=Базова котушка
+metaitem.voltage_coil.mv.name=Котушка середньої напруги
+metaitem.voltage_coil.mv.tooltip=Гарна котушка
+metaitem.voltage_coil.hv.name=Котушка високої напруги
+metaitem.voltage_coil.hv.tooltip=Покращена котушка
+metaitem.voltage_coil.ev.name=Котушка екстремальної напруги
+metaitem.voltage_coil.ev.tooltip=Екстремально гарна котушка
+metaitem.voltage_coil.iv.name=Котушка шаленої напруги
+metaitem.voltage_coil.iv.tooltip=Відмінна котушка
+metaitem.voltage_coil.luv.name=Котушка сміховинної напруги
+metaitem.voltage_coil.luv.tooltip=Відмінна котушка V2
+metaitem.voltage_coil.zpm.name=Котушка (ZPM)
+metaitem.voltage_coil.zpm.tooltip=Відмінна котушка V3
+metaitem.voltage_coil.uv.name=Котушка (UV)
+metaitem.voltage_coil.uv.tooltip=Доскональна котушка
+metaitem.voltage_coil.uhv.name=Котушка (UHV)
+metaitem.voltage_coil.uhv.tooltip=Ідеальна котушка
+metaitem.voltage_coil.uev.name=Котушка (UEV)
+metaitem.voltage_coil.uev.tooltip=Нереальна котушка
+metaitem.voltage_coil.uiv.name=Котушка (UIV)
+metaitem.voltage_coil.uiv.tooltip=Бездоганна котушка V2
+metaitem.voltage_coil.uxv.name=Котушка (UXV)
+metaitem.voltage_coil.uxv.tooltip=Бездоганна котушка V3
+metaitem.voltage_coil.opv.name=Котушка (OpV)
+metaitem.voltage_coil.opv.tooltip=Бездоганна котушка V4
+metaitem.voltage_coil.max.name=Катушка (MAX)
+metaitem.voltage_coil.max.tooltip=Максимальна котушка
+metaitem.liquid_fuel_jetpack.name=Реактивний ранець на рідкому паливі
+metaitem.liquid_fuel_jetpack.tooltip=Використовує паливо для тяги
+metaitem.electric_jetpack.name=Реактивний ранець з електричним двигуном
+metaitem.nightvision_goggles.name=Окуляри нічного бачення
+metaitem.nms.leggings.name=NanoMuscle™ Штани
+metaitem.nms.boots.name=NanoMuscle™ Чоботи
+metaitem.nms.helmet.name=NanoMuscle™ Шолом
+metaitem.nms.advanced_chestplate.name=Покращений NanoMuscle™ Нагрудник
+metaitem.qts.chestplate.name=QuarkTech™ Нагрудник
+metaitem.item_filter.tooltip=Фільтрує §fПредмети§7 працює як §fПокращення§7./nМожна виковистовувати для покращення §fКонвеєрного модуля§7 і §fРоботизованої руки§7.
+metaitem.smart_item_filter.tooltip=Фільтрує §fПредмети§7 за допомогою §fРецептів машин§7 працює як §fПокращення§7./nМожна виковистовувати для покращення §fКонвеєрного модуля§7 і §fРоботизованої руки§7.
+metaitem.qts.helmet.name=QuarkTech™ Шолом
+metaitem.qts.advanced_chestplate.name=Покращений QuarkTech™ Нагрудник
+metaitem.gravitation_engine.name=Модуль гравітаційного двигуна
+metaitem.tool.multiblock_builder.name=Конструктор багатоблочних конструкцій
+metaitem.tool.multiblock_builder.tooltip=Для налагодження та автоматичної збірки ваших багатоблочних конструкцій!
+metaitem.ore_dictionary_filter.tooltip=Фільтрує §fПредмети§7 з допомогою §fСловника руд§7 працює як §fПокращення§7./nМожна виковистовувати для покращення §fКонвеєрного модуля§7 і §fРоботизованої руки§7.
+metaarmor.nms.nightvision.enabled=NanoMuscle™ Костюм: Увімкнено нічне бачення
+metaarmor.nms.nightvision.disabled=NanoMuscle™ Костюм: Вимкнено нічне бачення
+metaitem.cover.controller.tooltip=§fВКЛ/ВИКЛ§7 машину працює як §fПокращення§7.
+metaitem.cover.activity.detector_advanced.tooltip=Видає §fПрогрес роботи§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.item.detector.advanced.tooltip=Видає §fСтатус зберігання предметів§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7, з можливістю контролювати з допомогою §fRS-Latch§7.
+metaitem.cover.energy.detector.advanced.tooltip=Дає §fRS-Latch§7 контроль за §fСтатусом енергії§7 за допомогою Редстоуну, працює як §fПокращення§7.
+metaitem.cover.energy.detector.name=Датчик енергії
+metaarmor.nms.nightvision.error=NanoMuscle™ Костюм: §cНедостатньо енергії!
+metaarmor.qts.nightvision.enabled=QuarkTech™ Костюм: Увімкнено нічне бачення
+metaitem.cover.fluid.detector.advanced.tooltip=Видає §fСтатус зберігання рідини§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7, з можливістю контролювати з допомогою §fRS-Latch§7.
+metaitem.cover.energy.detector.tooltip=Видає §fКількість енергії§7 у вигляді сигналу Редстоуна, працює як §fПокращення§7.
+metaitem.cover.fluid.voiding.advanced.tooltip=Видаляє §fРідини§7, з контролем кількості, працює як §fПокращення§7./nАктивується за допомогою §fМ'якої киянки§7 після розміщення.
+metaarmor.qts.nightvision.disabled=QuarkTech™ Костюм: Вимкнено нічне бачення
+metaarmor.jetpack.hover.enable=Реактивний ранець: Увімкнено режим зависання
+metaarmor.jetpack.hover.disable=Реактивний ранець: Вимкнено режим зависання
+metaarmor.jetpack.emergency_hover_mode=Аварійний режим зависання увімкнено!
+metaarmor.nms.share.enable=NanoMuscle™ Костюм: Зарядку ввімкнено
+metaarmor.nms.share.disable=NanoMuscle™ Костюм: Зарядку вимкнено
+metaarmor.nms.share.error=NanoMuscle™ Костюм: §cНе вистачає енергії для зарядки!
+metaarmor.qts.share.enable=QuarkTech™ Костюм: Зарядку ввімкнено
+metaarmor.qts.share.disable=QuarkTech™ Костюм: Зарядку вимкнено
+metaarmor.qts.share.error=QuarkTech™ Костюм: §cНе вистачає енергії для зарядки!
+metaarmor.message.nightvision.enabled=§bНічне бачення: §aУвімкнено
+metaarmor.message.nightvision.disabled=§bНічне бачення: §cВимкнено
+metaarmor.message.nightvision.error=§cНедостатньо енергії!
+metaarmor.tooltip.stepassist=Забезпечує крокову допомогу
+metaarmor.tooltip.speed=Збільшує швидкість бігу
+metaarmor.tooltip.jump=Збільшує висоту та дистанцію стрибків
+metaarmor.tooltip.falldamage=Обнуляє шкоду від падіння
+metaarmor.tooltip.potions=Обнуляє шкідливі ефекти
+metaarmor.tooltip.burning=Обнуляє горіння
+metaarmor.tooltip.breath=Поповнює шкалу підводого дихання
+metaarmor.tooltip.autoeat=Поповнює запаси їжі, використовуючи їжу з інвентарю
+metaarmor.hud.status.enabled=§aУВІМК
+metaarmor.hud.status.disabled=§cВИМК
+metaarmor.hud.energy_lvl=Рівень енергії: %s
+metaarmor.hud.fuel_lvl=Рівень палива: %s
+metaarmor.hud.hover_mode=Режим зависання: %s
+mataarmor.hud.supply_mode=Режим постачання: %s
+metaarmor.energy_share.error=Енергопостачання: §cНе вистачає потужності для зарядки приладів!
+metaarmor.energy_share.enable=Енергопостачання: Увімкнено заряджання приладів
+metaarmor.energy_share.disable=Енергопостачання: Вимкнено зарядку пристроїв
+metaarmor.energy_share.tooltip=Режим постачання: %s
+metaarmor.energy_share.tooltip.guide=Щоб змінити режим, клацніть SHIFT-ПКМ, утримуючи предмет
+metaitem.record.sus.name=Музичний диск
+metaitem.record.sus.tooltip=§7Leonz - Among Us Drip
+metaitem.nan.certificate.name=Сертифікат про те, що ви більше не новачок
+metaitem.nan.certificate.tooltip=Виклик прийнято!
+metaitem.fertilizer.name=Добриво
+metaitem.blacklight.name=Чорне світло
+metaitem.blacklight.tooltip=Довгохвильове §dУльтрафіолетове§7 джерело світла
+gui.widget.incrementButton.default_tooltip=Утримуйте Shift, Ctrl або обидві клавіші, щоб змінити кількість
+gui.widget.recipeProgressWidget.default_tooltip=Показати рецепти
+gregtech.recipe_memory_widget.tooltip.1=§7Клікніть лівою кнопкою миші, щоб автоматично внести цей рецепт до сітки крафтингу
+cover.filter.blacklist.disabled=Білий список
+cover.filter.blacklist.enabled=Чорний список
+cover.ore_dictionary_filter.title=Фільтр руди за словником
+cover.ore_dictionary_filter.match_all=Відповідає всім: %s
+cover.ore_dictionary_filter.case_sensitive=Чутливість до регістру: %s
+cover.ore_dictionary_filter.test_slot.info=Вставте елемент, щоб перевірити, чи відповідає він виразу фільтра
+cover.ore_dictionary_filter.test_slot.matches=§a* %s
+cover.ore_dictionary_filter.test_slot.matches_not=§c* %s
+cover.ore_dictionary_filter.test_slot.no_oredict.matches=§a(Немає словника руд)
+cover.ore_dictionary_filter.test_slot.no_oredict.matches_not=§c(Немає словника руд)
+cover.ore_dictionary_filter.status.err=§c%s помилка(и)
+cover.ore_dictionary_filter.status.err_warn=§c%s помилок та %s попереджень
+cover.ore_dictionary_filter.status.warn=§7%s попереджень
+cover.ore_dictionary_filter.status.no_issues=§aБез проблем
+cover.ore_dictionary_filter.status.explain=Пояснення рудного фільтра:
+cover.ore_dictionary_filter.button.case_sensitive.disabled=Нечутливий до регістру
+cover.ore_dictionary_filter.button.case_sensitive.enabled=Чутливий до регістру
+cover.ore_dictionary_filter.preview.next=... за яким слідує
+cover.ore_dictionary_filter.preview.match='%s'
+cover.ore_dictionary_filter.preview.match.not=не '%s'
+cover.ore_dictionary_filter.preview.char=1 символ
+cover.ore_dictionary_filter.preview.char.not=або більше ніж 1 символабо нічого
+cover.ore_dictionary_filter.preview.chars=%s символів
+cover.ore_dictionary_filter.preview.chars.not=або більше ніж або менше %s символів
+cover.ore_dictionary_filter.preview.chars_or_more=%s чи більше символів
+cover.ore_dictionary_filter.preview.chars_or_more.not=менше ніж %s символів
+cover.ore_dictionary_filter.preview.group=не:
+cover.ore_dictionary_filter.preview.or=один з...
+cover.ore_dictionary_filter.preview.nor=будьщо, що не є одним із...
+cover.ore_dictionary_filter.preview.or.entry=
+cover.ore_dictionary_filter.preview.or.entry.start=
+metaitem.cover.item.voiding.advanced.tooltip=Видаляє §fПредмети§7, з контролем кількості, працює як §fПокращення§7./nАктивується за допомогою §fМ'якої киянки§7 після розміщення.
+metaitem.cover.storage.tooltip=Невеликий сховище для зберігання дрібниць
+metaitem.cover.maintenance.detector.name=Датчик потреби технічного обслуговування
+metaitem.cover.activity.detector_advanced.name=Покращений датчик активності
+metaitem.cover.facade.tooltip=Декоративне оздоблення §fПокращення§7.
+metaitem.cover.crafting.tooltip=§fПокращений верстак§7 на машині, працює як §fПокращення§7.
+metaitem.cover.solar.panel.name=Сонячна панель (Покращення)
+metaitem.cover.solar.panel.lv.name=Сонячна панель низької напруги (Покращення)
+metaitem.cover.solar.panel.ev.name=Сонячна панель екстремальної напруги (Покращення)
+metaitem.cover.solar.panel.zpm.name=Сонячна панель модуля нульової точки (Покращення)
+metaitem.cover.solar.panel.tooltip.2=Виробляє §fЕнергію§7 з §eСонця§7, працює як §fПокращення§7.
+metaitem.dye.pink.name=Рожевий барвник
+metaitem.dye.yellow.name=Жовтий барвник
+metaitem.dye.light_blue.name=Світло-синій барвник
+metaitem.foam_sprayer.tooltip=Розпилює будівельну піну/nВикористовується на рамі для запінення з'єднаних рам/nПіна може бути кольоровою
+item.gt.tool.behavior.grass_path=§eЛандшафтник: §fСтворює доріжки
+item.gt.tool.behavior.plunger=§9Сантехнік: §fЗливає рідини
+gt.tool.class.wirecutter=Кусачки
+item.gt.tool.hammer.tooltip=§8Подрібнює блоки під час їх збирання
+item.gt.tool.knife.name=Ніж (%s)
+metaitem.cover.ender_fluid_link.tooltip=Передає §fРідини§7 за допомогою §fБезтрубового §dЕндер§f зв'яку§7, працює як §fПокращення§7.
+metaitem.dye.brown.name=Коричневий барвник
+metaitem.tool_parts_box.tooltip=Містить деякі частини інструментів/nПКМ для відкриття
+metaitem.compressed.coke_clay.name=Спресована коксова глина
+metaitem.wooden_form.brick.name=Дерев'яна форма для цегли
+item.gt.tool.behavior.silk_ice=§bЛьодоруб: §fШовковий дотик для льоду
+item.gt.tool.behavior.relocate_mining=§2Магніт: §fПритягує видобуті блоки
+item.gt.tool.behavior.damage_boost=§4Посилення шкоди: §fДодаткова шкода проти %s
+gt.tool.class.butchery_knife=Тесак
+item.gt.tool.wrench.tooltip=§8Утримуйте ліву кнопку миші, щоб демонтувати машини
+item.gt.tool.drill_mv.name=%s Бур (MV)
+item.gt.tool.wire_cutter_iv.name=%s Кусачки (IV)
+
+
+item.gt.tool.tooltip.crafting_uses=§aЗалишилося застосувань: %s
+item.gt.tool.harvest_level.1=§7Камінь
+item.gt.tool.mining_hammer.tooltip=§8Видобуває велику площу за один раз (якщо тільки ви не присідаєте)
+item.gt.tool.wrench_lv.name=
+item.gt.tool.wrench_hv.tooltip=§8Утримуйте ЛКМ, щоб демонтувати машини
+item.gt.tool.buzzsaw.tooltip=§8Не підходить для добування блоків
+item.gt.tool.tooltip.harvest_level=§eРівень збору: %s
+metaitem.advanced_electric_jetpack.name=Покращений реактивний ранець
+metaitem.nms.chestplate.name=NanoMuscle™ Нагрудник
+metaitem.qts.leggings.name=QuarkTech™ Штани
+metaarmor.qts.nightvision.error=QuarkTech™ Костюм: §cНедостатньо енергії!
+gregtech.recipe_memory_widget.tooltip.2=§7Нажміть Shift, щоб заблокувати/розблокувати цей рецепт
+metaitem.qts.boots.name=QuarkTech™ Чоботи
+metaitem.tool.multiblock_builder.tooltip2=SHIFT-ПКМ по контролеру мультиблочної структури, щоб автоматично побудувати її
From a91b37eb6448b8f11acf7618e87afea5c0cb1dbc Mon Sep 17 00:00:00 2001
From: iouter <62897714+iouter@users.noreply.github.com>
Date: Thu, 19 Sep 2024 12:01:21 +0800
Subject: [PATCH 3/7] Update zh_cn.lang (#2593)
---
.../resources/assets/gregtech/lang/zh_cn.lang | 49 +++++++++++++------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/src/main/resources/assets/gregtech/lang/zh_cn.lang b/src/main/resources/assets/gregtech/lang/zh_cn.lang
index fb68f3d3bf2..f3bc63c1658 100644
--- a/src/main/resources/assets/gregtech/lang/zh_cn.lang
+++ b/src/main/resources/assets/gregtech/lang/zh_cn.lang
@@ -1830,6 +1830,14 @@ gregtech.material.enriched_naquadah_sulfate=硫酸富集硅岩
gregtech.material.naquadria_sulfate=硫酸超能硅岩
gregtech.material.pyrochlore=烧绿石
gregtech.material.rtm_alloy=钌钨钼合金
+gregtech.material.ilmenite_slag=钛铁矿渣
+gregtech.material.zircon=锆石
+gregtech.material.zirconia=氧化锆
+gregtech.material.zirconium_tetrachloride=四氯化锆
+gregtech.material.hafnia=二氧化铪
+gregtech.material.hafnium_tetrachloride=四氯化铪
+gregtech.material.zircaloy_4=锆-4合金
+gregtech.material.inconel_718=因科镍-718
# Organic Chemistry Materials
@@ -2043,6 +2051,11 @@ gregtech.material.acidic_naquadria_solution=酸性超能硅岩溶液
gregtech.material.naquadria_waste=超能硅岩废液
gregtech.material.lapotron=兰波顿
gregtech.material.uu_matter=UU物质
+gregtech.material.bauxite_slurry=铝土浆液
+gregtech.material.cracked_bauxite_slurry=裂化铝土浆液
+gregtech.material.bauxite_sludge=铝土泥渣
+gregtech.material.decalcified_bauxite_sludge=脱钙铝土泥渣
+gregtech.material.bauxite_slag=铝土矿渣
# Second Degree Materials
@@ -2403,7 +2416,7 @@ tile.optical_pipe_normal.name=光缆
tile.optical_pipe_normal.tooltip1=传递§f算力§7或§f研究数据§7
tile.laser_pipe_normal.name=激光传导线缆
-tile.laser_pipe_normal.tooltip1=无线损地传递能量,只限直线摆放
+tile.laser_pipe_normal.tooltip1=§f无损§7传递能量,仅限直线摆放
metaitem.prospector.lv.name=电动勘探扫描仪(LV)
metaitem.prospector.hv.name=电动勘探扫描仪(HV)
@@ -4792,7 +4805,7 @@ gregtech.machine.large_miner.ev.name=基础采矿场
gregtech.machine.large_miner.iv.name=进阶采矿场
gregtech.machine.large_miner.luv.name=进阶采矿场 II
gregtech.machine.miner.multi.modes=具有精准采集模式与区块对齐模式。
-gregtech.machine.miner.multi.production=产出§f研磨机§7§f3x§7倍的粉碎矿石。
+gregtech.machine.miner.multi.production=它能产出§f三倍§7于§f研磨机§7的粉碎矿石。
gregtech.machine.miner.fluid_usage=每tick消耗§f%,d L§7的§f%s§7,超频时翻倍。
gregtech.machine.miner.multi.description=一台工作范围极广的多方块采矿机,能够提供巨量矿石。
gregtech.machine.miner.multi.needsfluid=钻井液不足!
@@ -4811,7 +4824,7 @@ gregtech.machine.miner.chunkradius=区块半径:%d
gregtech.machine.fluid_drilling_rig.mv.name=基础流体钻机
gregtech.machine.fluid_drilling_rig.hv.name=进阶流体钻机
gregtech.machine.fluid_drilling_rig.ev.name=进阶流体钻机 II
-gregtech.machine.fluid_drilling_rig.description=钻取基岩之下的涓涓流体。
+gregtech.machine.fluid_drilling_rig.description=钻取基岩之下的漫漫流体。
gregtech.machine.fluid_drilling_rig.production=§e产量倍数:§f%dx,超频时为%fx
gregtech.machine.fluid_drilling_rig.depletion=§b损耗率:§f%s%%
gregtech.machine.fluid_drilling_rig.shows_depletion=显示流体矿脉信息
@@ -5149,9 +5162,9 @@ gregtech.maintenance.configurable_duration=处理耗时:%fx
gregtech.maintenance.configurable_duration.unchanged_description=配方以正常速度运行。更改配置以更新。
gregtech.maintenance.configurable_duration.changed_description=配方处理速度现为正常速度(不计超频)的%f倍。
-gregtech.maintenance.configurable_time=故障几率:%fx
-gregtech.maintenance.configurable_time.unchanged_description=故障的发生几率为正常值。更改配置以更新。
-gregtech.maintenance.configurable_time.changed_description=故障的发生几率现为正常值的%f倍。
+gregtech.maintenance.configurable_time=故障概率:%fx
+gregtech.maintenance.configurable_time.unchanged_description=故障的发生概率为正常值。更改配置以更新。
+gregtech.maintenance.configurable_time.changed_description=故障的发生概率现为正常值的%f倍。
gregtech.maintenance.configurable.tooltip_basic=以更频繁的维护需求为代价,加快机器的处理速度
gregtech.maintenance.configurable.tooltip_more_info=按住SHIFT进行特殊交互
@@ -5177,7 +5190,7 @@ gregtech.machine.muffler_hatch.uxv.name=§eUXV§r消声仓
gregtech.machine.muffler_hatch.opv.name=§9OpV§r消声仓
gregtech.machine.muffler_hatch.max.name=§c§lMAX§r消声仓
-gregtech.muffler.recovery_tooltip=§b收集几率:§f%d%%
+gregtech.muffler.recovery_tooltip=§b收集概率:§f%d%%
gregtech.machine.pump_hatch.name=水泵输出仓
gregtech.machine.pump_hatch.tooltip=原始水泵专用流体输出口
@@ -5289,7 +5302,7 @@ gregtech.machine.laser_hatch.target.tooltip1=远距离接收能量
gregtech.machine.laser_hatch.tooltip2=§c激光传导线缆必须直线摆放!§7
gregtech.machine.fluid_tank.max_multiblock=多方块结构最大尺寸:%,dx%,dx%,d
-gregtech.machine.fluid_tank.fluid=含有%s mB%s
+gregtech.machine.fluid_tank.fluid=含有%s L%s
# ME Parts
gregtech.machine.me_import_item_bus.name=ME输入总线
@@ -5493,14 +5506,14 @@ fluid.spawnlocation.name=流体矿脉信息
gregtech.jei.fluid.vein_weight=矿脉权重:%d
gregtech.jei.fluid.min_yield=最小产量:%d
gregtech.jei.fluid.max_yield=最大产量:%d
-gregtech.jei.fluid.depletion_chance=消耗几率:%d%%
+gregtech.jei.fluid.depletion_chance=消耗概率:%d%%
gregtech.jei.fluid.depletion_amount=消耗量:%d
gregtech.jei.fluid.depleted_rate=殆尽后产量:%d
gregtech.jei.fluid.dimension=维度:
gregtech.jei.fluid.weight_hover=流体矿脉的生成权重。鼠标悬于图标可查看该流体在特定生物群系中特殊的生成权重
gregtech.jei.fluid.min_hover=流体矿脉所能具有的的最小产量
gregtech.jei.fluid.max_hover=流体矿脉所能具有的的最大产量
-gregtech.jei.fluid.dep_chance_hover=开采流体矿脉时消耗的几率
+gregtech.jei.fluid.dep_chance_hover=开采流体矿脉时消耗的概率
gregtech.jei.fluid.dep_amount_hover=消耗后消耗的量
gregtech.jei.fluid.dep_yield_hover=流体矿脉殆尽后能开采的最大流体量
@@ -5658,7 +5671,7 @@ gregtech.multiblock.large_combustion_engine.supply_liquid_oxygen_to_boost=提供
gregtech.multiblock.large_combustion_engine.obstructed=引擎进气口受阻!
gregtech.multiblock.large_combustion_engine.obstructed.desc=引擎进气口前方必须有一格空气。
-gregtech.multiblock.turbine.fuel_amount=燃料量:%s mB(%s)
+gregtech.multiblock.turbine.fuel_amount=燃料量:%s L(%s)
gregtech.multiblock.turbine.fuel_needed=消耗量:%s / %s ticks
gregtech.multiblock.turbine.rotor_speed=转子转速:%s
gregtech.multiblock.turbine.rotor_rpm_unit_name=RPM
@@ -5748,14 +5761,14 @@ gregtech.multiblock.hpca.warning_multiple_bridges=- 多个桥接组件(没有
gregtech.multiblock.hpca.warning_no_computation=- 没有计算组件
gregtech.multiblock.hpca.warning_low_cooling=- 冷却不足
gregtech.multiblock.hpca.info_max_computation=最大算力:%s
-gregtech.multiblock.hpca.info_max_cooling_demand=冷却液需求:%s
-gregtech.multiblock.hpca.info_max_cooling_available=冷却液可用:%s
-gregtech.multiblock.hpca.info_max_coolant_required=冷却液还需:%s
+gregtech.multiblock.hpca.info_max_cooling_demand=冷却需求:%s
+gregtech.multiblock.hpca.info_max_cooling_available=冷却可用:%s
+gregtech.multiblock.hpca.info_max_coolant_required=冷却液需求:%s L/t
gregtech.multiblock.hpca.info_coolant_name=多氯联苯冷却液
gregtech.multiblock.hpca.info_bridging_enabled=桥接已启动
gregtech.multiblock.hpca.info_bridging_disabled=桥接已关闭
-gregtech.command.usage=用法:/gregtech
+gregtech.command.usage=用法:/gregtech
gregtech.command.worldgen.usage=用法:/gregtech worldgen
gregtech.command.worldgen.reload.usage=用法:/gregtech worldgen reload
gregtech.command.worldgen.reload.success=已从配置文件中重载世界生成设定。
@@ -5782,6 +5795,12 @@ gregtech.command.copy.copied_and_click=已复制至剪贴板。点击以再次
gregtech.command.copy.click_to_copy=点击以复制
gregtech.command.copy.copied_start=已复制[
gregtech.command.copy.copied_end=]至剪贴板
+gregtech.command.datafix.usage=用法:/gregtech datafix
+gregtech.command.datafix.bqu.usage=用法:/gregtech datafix [confirm]
+gregtech.command.datafix.bqu.backup=备份你的存档和BQu配置文件,然后使用“confirm”参数重新运行
+gregtech.command.datafix.bqu.start=开始迁移BQu任务数据库…
+gregtech.command.datafix.bqu.complete=BQu任务数据库迁移完成
+gregtech.command.datafix.bqu.failed=BQu任务数据库迁移失败。恢复你的备份!
gregtech.chat.cape=§5恭喜你:你刚刚解锁了一件新披风!查看终端应用程序“披风选择器”来使用它。§r
From e62a3822ca04fd02824ecd5c33605061da4acdf8 Mon Sep 17 00:00:00 2001
From: Zorbatron
Date: Thu, 19 Sep 2024 00:43:07 -0400
Subject: [PATCH 4/7] Add a config option for the magnet's attraction delay
(#2616)
---
src/main/java/gregtech/common/ConfigHolder.java | 14 +++++++++++++-
.../common/items/behaviors/ItemMagnetBehavior.java | 3 ++-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/main/java/gregtech/common/ConfigHolder.java b/src/main/java/gregtech/common/ConfigHolder.java
index caf04defc48..7127a2ab688 100644
--- a/src/main/java/gregtech/common/ConfigHolder.java
+++ b/src/main/java/gregtech/common/ConfigHolder.java
@@ -35,7 +35,6 @@ public class ConfigHolder {
// TODO move to ToolsModule config
@Config.Comment("Config options for Tools and Armor")
@Config.Name("Tool and Armor Options")
- @Config.RequiresMcRestart
public static ToolOptions tools = new ToolOptions();
@Config.Comment("Config options for World Generation features")
@@ -641,34 +640,42 @@ public static class HeatEffectBloom {
public static class ToolOptions {
+ @Config.RequiresMcRestart
@Config.Name("NanoSaber Options")
public NanoSaber nanoSaber = new NanoSaber();
+ @Config.RequiresMcRestart
@Config.Comment("NightVision Goggles Voltage Tier. Default: 1 (LV)")
@Config.RangeInt(min = 0, max = 14)
public int voltageTierNightVision = 1;
+ @Config.RequiresMcRestart
@Config.Comment("NanoSuit Voltage Tier. Default: 3 (HV)")
@Config.RangeInt(min = 0, max = 14)
public int voltageTierNanoSuit = 3;
+ @Config.RequiresMcRestart
@Config.Comment({ "Advanced NanoSuit Chestplate Voltage Tier.", "Default: 3 (HV)" })
@Config.RangeInt(min = 0, max = 14)
public int voltageTierAdvNanoSuit = 3;
+ @Config.RequiresMcRestart
@Config.Comment({ "QuarkTech Suit Voltage Tier.", "Default: 5 (IV)" })
@Config.RangeInt(min = 0, max = 14)
@Config.SlidingOption
public int voltageTierQuarkTech = 5;
+ @Config.RequiresMcRestart
@Config.Comment({ "Advanced QuarkTech Suit Chestplate Voltage Tier.", "Default: 5 (LuV)" })
@Config.RangeInt(min = 0, max = 14)
public int voltageTierAdvQuarkTech = 6;
+ @Config.RequiresMcRestart
@Config.Comment({ "Electric Impeller Jetpack Voltage Tier.", "Default: 2 (MV)" })
@Config.RangeInt(min = 0, max = 14)
public int voltageTierImpeller = 2;
+ @Config.RequiresMcRestart
@Config.Comment({ "Advanced Electric Jetpack Voltage Tier.", "Default: 3 (HV)" })
@Config.RangeInt(min = 0, max = 14)
public int voltageTierAdvImpeller = 3;
@@ -680,6 +687,11 @@ public static class ToolOptions {
@Config.Comment("Armor HUD Location")
public ArmorHud armorHud = new ArmorHud();
+
+ @Config.Comment({ "How often items should be moved by a magnet", "Default: 10 ticks" })
+ @Config.RangeInt(min = 1, max = 100)
+ @Config.SlidingOption
+ public int magnetDelay = 10;
}
public static class ArmorHud {
diff --git a/src/main/java/gregtech/common/items/behaviors/ItemMagnetBehavior.java b/src/main/java/gregtech/common/items/behaviors/ItemMagnetBehavior.java
index f5ce22ba925..bd0adea08e7 100644
--- a/src/main/java/gregtech/common/items/behaviors/ItemMagnetBehavior.java
+++ b/src/main/java/gregtech/common/items/behaviors/ItemMagnetBehavior.java
@@ -6,6 +6,7 @@
import gregtech.api.items.metaitem.MetaItem;
import gregtech.api.items.metaitem.stats.IItemBehaviour;
import gregtech.api.util.Mods;
+import gregtech.common.ConfigHolder;
import gregtech.integration.baubles.BaublesModule;
import net.minecraft.client.resources.I18n;
@@ -81,7 +82,7 @@ private static boolean toggleActive(ItemStack stack) {
public void onUpdate(ItemStack stack, Entity entity) {
// Adapted logic from Draconic Evolution
// https://github.com/Draconic-Inc/Draconic-Evolution/blob/1.12.2/src/main/java/com/brandon3055/draconicevolution/items/tools/Magnet.java
- if (!entity.isSneaking() && entity.ticksExisted % 10 == 0 && isActive(stack) &&
+ if (!entity.isSneaking() && entity.ticksExisted % ConfigHolder.tools.magnetDelay == 0 && isActive(stack) &&
entity instanceof EntityPlayer player) {
World world = entity.getEntityWorld();
if (!drainEnergy(true, stack, energyDraw)) {
From 11f752a3e07b27cad151f8ccdf609e8cdb7e28f8 Mon Sep 17 00:00:00 2001
From: ALongStringOfNumbers
<31759736+ALongStringOfNumbers@users.noreply.github.com>
Date: Wed, 18 Sep 2024 22:15:03 -0700
Subject: [PATCH 5/7] Attempt to fix tools from addon materials (#2585)
---
.../gregtech/api/items/toolitem/ToolHelper.java | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/main/java/gregtech/api/items/toolitem/ToolHelper.java b/src/main/java/gregtech/api/items/toolitem/ToolHelper.java
index 23d3145ca9b..8b1a8ef147a 100644
--- a/src/main/java/gregtech/api/items/toolitem/ToolHelper.java
+++ b/src/main/java/gregtech/api/items/toolitem/ToolHelper.java
@@ -18,7 +18,13 @@
import gregtech.tools.enchants.EnchantmentHardHammer;
import net.minecraft.advancements.CriteriaTriggers;
-import net.minecraft.block.*;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockCommandBlock;
+import net.minecraft.block.BlockLiquid;
+import net.minecraft.block.BlockPane;
+import net.minecraft.block.BlockRailBase;
+import net.minecraft.block.BlockStructure;
+import net.minecraft.block.BlockWeb;
import net.minecraft.block.state.IBlockState;
import net.minecraft.enchantment.EnchantmentDurability;
import net.minecraft.enchantment.EnchantmentHelper;
@@ -57,7 +63,11 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
import java.util.function.Supplier;
import static gregtech.api.GTValues.LV;
@@ -196,7 +206,7 @@ public static ItemStack getAndSetToolData(IGTTool tool, Material material, int m
ItemStack stack = tool.getRaw();
GTUtility.getOrCreateNbtCompound(stack).setInteger(HIDE_FLAGS, 2);
NBTTagCompound toolTag = getToolTag(stack);
- toolTag.setString(MATERIAL_KEY, material.toString());
+ toolTag.setString(MATERIAL_KEY, material.getRegistryName());
toolTag.setInteger(MAX_DURABILITY_KEY, maxDurability);
toolTag.setInteger(HARVEST_LEVEL_KEY, harvestLevel);
toolTag.setFloat(TOOL_SPEED_KEY, toolSpeed);
From 4479f8fab0a9a30da91aa14459c92fb91b683bb8 Mon Sep 17 00:00:00 2001
From: Zorbatron
Date: Thu, 19 Sep 2024 11:53:11 -0400
Subject: [PATCH 6/7] Port the GT5u ME hatch wirecutter behavior (#2618)
---
.../api/metatileentity/MetaTileEntity.java | 13 +++++
.../appeng/MetaTileEntityAEHostablePart.java | 54 +++++++++++++++++--
.../appeng/MetaTileEntityMEInputBus.java | 1 +
.../appeng/MetaTileEntityMEInputHatch.java | 1 +
.../appeng/MetaTileEntityMEOutputBus.java | 1 +
.../appeng/MetaTileEntityMEOutputHatch.java | 1 +
.../appeng/MetaTileEntityMEStockingBus.java | 1 +
.../appeng/MetaTileEntityMEStockingHatch.java | 1 +
.../resources/assets/gregtech/lang/en_us.lang | 3 ++
9 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
index 1185fb5ab97..24649f1d1f5 100644
--- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
+++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java
@@ -584,6 +584,9 @@ public final boolean onToolClick(EntityPlayer playerIn, @NotNull Set too
if (toolClasses.contains(ToolClasses.HARD_HAMMER)) {
return onHardHammerClick(playerIn, hand, gridSideHit, hitResult);
}
+ if (toolClasses.contains(ToolClasses.WIRE_CUTTER)) {
+ return onWireCutterClick(playerIn, hand, gridSideHit, hitResult);
+ }
return false;
}
@@ -664,6 +667,16 @@ public boolean onHardHammerClick(EntityPlayer playerIn, EnumHand hand, EnumFacin
return true;
}
+ /**
+ * Called when player clicks a wire cutter on specific side of this meta tile entity
+ *
+ * @return true if something happened, so the tool will get damaged and animation will be played
+ */
+ public boolean onWireCutterClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing,
+ CuboidRayTraceResult hitResult) {
+ return false;
+ }
+
public void onLeftClick(EntityPlayer player, EnumFacing facing, CuboidRayTraceResult hitResult) {
if (this instanceof IDataStickIntractable dsi) {
ItemStack stack = player.getHeldItemMainhand();
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java
index c71b4acf74e..fbe7e8ff674 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java
@@ -4,11 +4,14 @@
import gregtech.common.ConfigHolder;
import gregtech.common.metatileentities.multi.multiblockpart.MetaTileEntityMultiblockNotifiablePart;
+import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.EnumFacing;
+import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.text.TextComponentTranslation;
import appeng.api.AEApi;
import appeng.api.networking.GridFlags;
@@ -24,6 +27,7 @@
import appeng.me.helpers.BaseActionSource;
import appeng.me.helpers.IGridProxyable;
import appeng.me.helpers.MachineSource;
+import codechicken.lib.raytracer.CuboidRayTraceResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,12 +44,14 @@ public abstract class MetaTileEntityAEHostablePart> extend
private AENetworkProxy aeProxy;
private int meUpdateTick;
protected boolean isOnline;
+ private boolean allowExtraConnections;
public MetaTileEntityAEHostablePart(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch,
Class extends IStorageChannel> storageChannel) {
super(metaTileEntityId, tier, isExportHatch);
this.meUpdateTick = 0;
this.storageChannel = storageChannel;
+ this.allowExtraConnections = false;
}
@Override
@@ -76,6 +82,7 @@ public void writeInitialSyncData(PacketBuffer buf) {
}
buf.writeInt(this.meUpdateTick);
buf.writeBoolean(this.isOnline);
+ buf.writeBoolean(this.allowExtraConnections);
}
@Override
@@ -95,6 +102,7 @@ public void receiveInitialSyncData(PacketBuffer buf) {
}
this.meUpdateTick = buf.readInt();
this.isOnline = buf.readBoolean();
+ this.allowExtraConnections = buf.readBoolean();
}
@Override
@@ -112,7 +120,7 @@ public void receiveCustomData(int dataId, PacketBuffer buf) {
@NotNull
@Override
public AECableType getCableConnectionType(@NotNull AEPartLocation part) {
- if (part.getFacing() != this.frontFacing) {
+ if (part.getFacing() != this.frontFacing && !this.allowExtraConnections) {
return AECableType.NONE;
}
return AECableType.SMART;
@@ -133,9 +141,7 @@ public AENetworkProxy getProxy() {
@Override
public void setFrontFacing(EnumFacing frontFacing) {
super.setFrontFacing(frontFacing);
- if (this.aeProxy != null) {
- this.aeProxy.setValidSides(EnumSet.of(this.getFrontFacing()));
- }
+ updateConnectableSides();
}
@Override
@@ -174,7 +180,7 @@ private AENetworkProxy createProxy() {
AENetworkProxy proxy = new AENetworkProxy(holder, "mte_proxy", this.getStackForm(), true);
proxy.setFlags(GridFlags.REQUIRE_CHANNEL);
proxy.setIdlePowerUsage(ConfigHolder.compat.ae2.meHatchEnergyUsage);
- proxy.setValidSides(EnumSet.of(this.getFrontFacing()));
+ proxy.setValidSides(getConnectableSides());
return proxy;
}
return null;
@@ -198,4 +204,42 @@ protected IMEMonitor getMonitor() {
return null;
}
}
+
+ public EnumSet getConnectableSides() {
+ return this.allowExtraConnections ? EnumSet.allOf(EnumFacing.class) : EnumSet.of(getFrontFacing());
+ }
+
+ public void updateConnectableSides() {
+ if (this.aeProxy != null) {
+ this.aeProxy.setValidSides(getConnectableSides());
+ }
+ }
+
+ @Override
+ public boolean onWireCutterClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing,
+ CuboidRayTraceResult hitResult) {
+ this.allowExtraConnections = !this.allowExtraConnections;
+ updateConnectableSides();
+
+ if (!getWorld().isRemote) {
+ playerIn.sendStatusMessage(new TextComponentTranslation(this.allowExtraConnections ?
+ "gregtech.machine.me.extra_connections.enabled" : "gregtech.machine.me.extra_connections.disabled"),
+ true);
+ }
+
+ return true;
+ }
+
+ @Override
+ public NBTTagCompound writeToNBT(NBTTagCompound data) {
+ super.writeToNBT(data);
+ data.setBoolean("AllowExtraConnections", this.allowExtraConnections);
+ return data;
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound data) {
+ super.readFromNBT(data);
+ this.allowExtraConnections = data.getBoolean("AllowExtraConnections");
+ }
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java
index 3d4fea9abc0..b1e53f22f4a 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java
@@ -320,6 +320,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.me.item_import.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me_import_item_hatch.configs.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.copy_paste.tooltip"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java
index 4e510077787..2bcdc10f542 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java
@@ -260,6 +260,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.me.fluid_import.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me_import_fluid_hatch.configs.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.copy_paste.tooltip"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java
index 853321014f9..9e008b857e3 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java
@@ -186,6 +186,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.item_bus.export.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.item_export.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.item_export.tooltip.2"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java
index f22c489909b..26a8fcc7947 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java
@@ -188,6 +188,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.fluid_hatch.export.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.fluid_export.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.fluid_export.tooltip.2"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java
index f8bd7a5850a..640f7869617 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java
@@ -360,6 +360,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.me_import_item_hatch.configs.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.copy_paste.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.stocking_item.tooltip.2"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java
index fcc9e1e7d12..30e28eff54b 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java
@@ -265,6 +265,7 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis
tooltip.add(I18n.format("gregtech.machine.me_import_fluid_hatch.configs.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.copy_paste.tooltip"));
tooltip.add(I18n.format("gregtech.machine.me.stocking_fluid.tooltip.2"));
+ tooltip.add(I18n.format("gregtech.machine.me.extra_connections.tooltip"));
tooltip.add(I18n.format("gregtech.universal.enabled"));
}
diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang
index 042607af612..5c78797a406 100644
--- a/src/main/resources/assets/gregtech/lang/en_us.lang
+++ b/src/main/resources/assets/gregtech/lang/en_us.lang
@@ -5340,6 +5340,9 @@ gregtech.machine.me.import_copy_settings=Saved settings to Data Stick
gregtech.machine.me.import_paste_settings=Applied settings from Data Stick
gregtech.machine.me.item_import.data_stick.name=§oME Input Bus Configuration Data
gregtech.machine.me.fluid_import.data_stick.name=§oME Input Hatch Configuration Data
+gregtech.machine.me.extra_connections.enabled=Allow connections from all sides
+gregtech.machine.me.extra_connections.disabled=Allow connection only on front face
+gregtech.machine.me.extra_connections.tooltip=Right-click with wire cutters to allow connecting to AE2 on all sides
# Universal tooltips
gregtech.universal.tooltip.voltage_in=§aVoltage IN: §f%,d EU/t (%s§f)
From efd861770802097cb10ecb4c731d72223f131756 Mon Sep 17 00:00:00 2001
From: TechLord22 <37029404+TechLord22@users.noreply.github.com>
Date: Thu, 19 Sep 2024 13:32:53 -0400
Subject: [PATCH 7/7] clean up recipe property storage (#2607)
---
src/main/java/gregtech/api/GregTechAPI.java | 2 +
.../api/block/IHeatingCoilBlockStats.java | 2 +-
.../capability/impl/AbstractRecipeLogic.java | 26 ++--
.../impl/ComputationRecipeLogic.java | 9 +-
.../api/capability/impl/FuelRecipeLogic.java | 4 +-
.../impl/HeatingCoilRecipeLogic.java | 12 +-
.../impl/MultiblockFuelRecipeLogic.java | 6 +-
.../impl/MultiblockRecipeLogic.java | 8 +-
.../capability/impl/PrimitiveRecipeLogic.java | 4 +-
.../capability/impl/RecipeLogicEnergy.java | 4 +-
.../java/gregtech/api/recipes/Recipe.java | 61 +++-----
.../gregtech/api/recipes/RecipeBuilder.java | 95 +++++-------
.../builders/AssemblyLineRecipeBuilder.java | 18 +--
.../recipes/builders/BlastRecipeBuilder.java | 9 +-
.../builders/ComputationRecipeBuilder.java | 8 +-
.../recipes/builders/FusionRecipeBuilder.java | 9 +-
.../builders/ImplosionRecipeBuilder.java | 62 ++++----
.../builders/PrimitiveRecipeBuilder.java | 2 +-
.../machines/RecipeMapAssemblyLine.java | 28 ++--
.../RecipeProperty.java | 45 ++++--
.../properties/RecipePropertyRegistry.java | 29 ++++
.../properties/RecipePropertyStorage.java | 119 +++++++++++++++
.../properties/RecipePropertyStorageImpl.java | 111 ++++++++++++++
.../impl}/CleanroomProperty.java | 29 ++--
.../impl}/ComputationProperty.java | 24 ++-
.../impl}/DimensionProperty.java | 47 ++++--
.../impl}/FusionEUToStartProperty.java | 22 ++-
.../impl}/ImplosionExplosiveProperty.java | 24 ++-
.../impl}/PrimitiveProperty.java | 24 ++-
.../impl}/ResearchProperty.java | 28 +++-
.../impl}/ResearchPropertyData.java | 22 ++-
.../impl}/ScanProperty.java | 20 ++-
.../impl}/TemperatureProperty.java | 19 ++-
.../impl}/TotalComputationProperty.java | 24 ++-
.../recipeproperties/DefaultProperty.java | 19 ---
.../EmptyRecipePropertyStorage.java | 65 ---------
.../IRecipePropertyStorage.java | 60 --------
.../RecipePropertyStorage.java | 134 -----------------
.../gregtech/api/recipes/ui/RecipeMapUI.java | 6 +-
.../api/util/AssemblyLineManager.java | 2 +-
.../java/gregtech/common/CommonProxy.java | 2 +-
.../electric/MetaTileEntityAssemblyLine.java | 2 +-
.../electric/MetaTileEntityCrackingUnit.java | 4 +-
.../MetaTileEntityElectricBlastFurnace.java | 2 +-
.../electric/MetaTileEntityFusionReactor.java | 8 +-
.../electric/MetaTileEntityMultiSmelter.java | 4 +-
.../MetaTileEntityProcessingArray.java | 4 +-
.../electric/MetaTileEntityPyrolyseOven.java | 4 +-
src/main/java/gregtech/core/CoreModule.java | 2 +-
.../crafttweaker/recipe/CTRecipe.java | 11 --
.../crafttweaker/recipe/CTRecipeBuilder.java | 12 +-
.../integration/groovy/GroovyExpansions.java | 2 +-
.../jei/basic/MaterialTreeCategory.java | 2 +-
.../jei/recipe/GTRecipeWrapper.java | 29 ++--
.../jei/recipe/RecipeMapCategory.java | 8 +-
.../handlers/MaterialRecipeHandler.java | 8 +-
.../RecipePropertyStorageTest.java | 138 ------------------
57 files changed, 734 insertions(+), 750 deletions(-)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties}/RecipeProperty.java (62%)
create mode 100644 src/main/java/gregtech/api/recipes/properties/RecipePropertyRegistry.java
create mode 100644 src/main/java/gregtech/api/recipes/properties/RecipePropertyStorage.java
create mode 100644 src/main/java/gregtech/api/recipes/properties/RecipePropertyStorageImpl.java
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/CleanroomProperty.java (63%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/ComputationProperty.java (53%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/DimensionProperty.java (63%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/FusionEUToStartProperty.java (74%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/ImplosionExplosiveProperty.java (55%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/PrimitiveProperty.java (55%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/ResearchProperty.java (50%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/ResearchPropertyData.java (66%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/ScanProperty.java (56%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/TemperatureProperty.java (79%)
rename src/main/java/gregtech/api/recipes/{recipeproperties => properties/impl}/TotalComputationProperty.java (56%)
delete mode 100644 src/main/java/gregtech/api/recipes/recipeproperties/DefaultProperty.java
delete mode 100644 src/main/java/gregtech/api/recipes/recipeproperties/EmptyRecipePropertyStorage.java
delete mode 100644 src/main/java/gregtech/api/recipes/recipeproperties/IRecipePropertyStorage.java
delete mode 100644 src/main/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorage.java
delete mode 100644 src/test/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorageTest.java
diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java
index 01845f8b047..4e3bc8bc69c 100644
--- a/src/main/java/gregtech/api/GregTechAPI.java
+++ b/src/main/java/gregtech/api/GregTechAPI.java
@@ -11,6 +11,7 @@
import gregtech.api.metatileentity.registry.MTEManager;
import gregtech.api.modules.IModuleManager;
import gregtech.api.network.INetworkHandler;
+import gregtech.api.recipes.properties.RecipePropertyRegistry;
import gregtech.api.sound.ISoundManager;
import gregtech.api.unification.material.Material;
import gregtech.api.unification.material.registry.IMaterialRegistryManager;
@@ -56,6 +57,7 @@ public class GregTechAPI {
public static MTEManager mteManager;
/** GT's data migrations API */
public static final MigrationAPI MIGRATIONS = new MigrationAPI();
+ public static final RecipePropertyRegistry RECIPE_PROPERTIES = new RecipePropertyRegistry();
/** Will be available at the Pre-Initialization stage */
private static boolean highTier;
diff --git a/src/main/java/gregtech/api/block/IHeatingCoilBlockStats.java b/src/main/java/gregtech/api/block/IHeatingCoilBlockStats.java
index 5f6e5c49c06..0e2b7427591 100644
--- a/src/main/java/gregtech/api/block/IHeatingCoilBlockStats.java
+++ b/src/main/java/gregtech/api/block/IHeatingCoilBlockStats.java
@@ -1,6 +1,6 @@
package gregtech.api.block;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import gregtech.api.unification.material.Material;
import org.jetbrains.annotations.NotNull;
diff --git a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
index ced966ccc48..455ae3afd47 100644
--- a/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/AbstractRecipeLogic.java
@@ -18,9 +18,9 @@
import gregtech.api.recipes.logic.IParallelableRecipeLogic;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.CleanroomProperty;
-import gregtech.api.recipes.recipeproperties.DimensionProperty;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.impl.CleanroomProperty;
+import gregtech.api.recipes.properties.impl.DimensionProperty;
import gregtech.api.util.GTLog;
import gregtech.api.util.GTTransferUtils;
import gregtech.api.util.GTUtility;
@@ -441,9 +441,11 @@ protected boolean checkCleanroomRequirement(@NotNull Recipe recipe) {
}
protected boolean checkDimensionRequirement(@NotNull Recipe recipe) {
- if (!recipe.hasProperty(DimensionProperty.getInstance())) return true;
- return recipe.getProperty(DimensionProperty.getInstance(), DimensionProperty.DimensionPropertyList.EMPTY_LIST)
- .checkDimension(this.getMetaTileEntity().getWorld().provider.getDimension());
+ DimensionProperty.DimensionPropertyList list = recipe.getProperty(DimensionProperty.getInstance(), null);
+ if (list == null) {
+ return true;
+ }
+ return list.checkDimension(this.getMetaTileEntity().getWorld().provider.getDimension());
}
/**
@@ -682,7 +684,7 @@ protected static boolean areItemStacksEqual(@NotNull ItemStack stackA, @NotNull
@NotNull IMultipleTankHandler importFluids) {
calculateOverclock(recipe);
- modifyOverclockPost(ocResult, recipe.getRecipePropertyStorage());
+ modifyOverclockPost(ocResult, recipe.propertyStorage());
if (ocResult.parallel() > 1) {
recipe = subTickOC(ocResult, recipe, importInventory, importFluids);
@@ -814,7 +816,7 @@ protected boolean hasEnoughPower(long eut, int duration) {
* @param ocResult The overclock result
* @param storage the RecipePropertyStorage of the recipe being processed
*/
- protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull IRecipePropertyStorage storage) {}
+ protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull RecipePropertyStorage storage) {}
/**
* Calculates the overclocked Recipe's final duration and EU/t
@@ -837,13 +839,13 @@ protected final void calculateOverclock(@NotNull Recipe recipe) {
* @param ocResult the result of overclocking
*/
protected void performOverclocking(@NotNull Recipe recipe, @NotNull OCParams ocParams, @NotNull OCResult ocResult) {
- modifyOverclockPre(ocParams, recipe.getRecipePropertyStorage());
+ modifyOverclockPre(ocParams, recipe.propertyStorage());
if (ocParams.ocAmount() <= 0) {
// number of OCs is <= 0, so do not overclock
ocResult.init(ocParams.eut(), ocParams.duration());
} else {
- runOverclockingLogic(ocParams, ocResult, recipe.getRecipePropertyStorage(), getMaximumOverclockVoltage());
+ runOverclockingLogic(ocParams, ocResult, recipe.propertyStorage(), getMaximumOverclockVoltage());
}
}
@@ -873,7 +875,7 @@ protected int getNumberOfOCs(long recipeEUt) {
* @param ocParams an array of [recipeEUt, recipeDuration, numberOfOCs]
* @param storage the RecipePropertyStorage of the recipe being processed
*/
- protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePropertyStorage storage) {}
+ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull RecipePropertyStorage storage) {}
/**
* Calls the desired overclocking logic to be run for the recipe. Performs the actual overclocking on the provided
@@ -885,7 +887,7 @@ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePr
* @param maxVoltage the maximum voltage the recipe is allowed to be run at
*/
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
standardOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(), getOverclockingVoltageFactor());
}
diff --git a/src/main/java/gregtech/api/capability/impl/ComputationRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/ComputationRecipeLogic.java
index 99284729017..67c3c03fbc9 100644
--- a/src/main/java/gregtech/api/capability/impl/ComputationRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/ComputationRecipeLogic.java
@@ -4,8 +4,8 @@
import gregtech.api.capability.IOpticalComputationReceiver;
import gregtech.api.metatileentity.multiblock.RecipeMapMultiblockController;
import gregtech.api.recipes.Recipe;
-import gregtech.api.recipes.recipeproperties.ComputationProperty;
-import gregtech.api.recipes.recipeproperties.TotalComputationProperty;
+import gregtech.api.recipes.properties.impl.ComputationProperty;
+import gregtech.api.recipes.properties.impl.TotalComputationProperty;
import net.minecraft.nbt.NBTTagCompound;
@@ -49,11 +49,12 @@ public boolean checkRecipe(@NotNull Recipe recipe) {
if (!super.checkRecipe(recipe)) {
return false;
}
- if (!recipe.hasProperty(ComputationProperty.getInstance())) {
+ int recipeCWUt = recipe.getProperty(ComputationProperty.getInstance(), 0);
+ if (recipeCWUt == 0) {
return true;
}
+
IOpticalComputationProvider provider = getComputationProvider();
- int recipeCWUt = recipe.getProperty(ComputationProperty.getInstance(), 0);
return provider.requestCWUt(recipeCWUt, true) >= recipeCWUt;
}
diff --git a/src/main/java/gregtech/api/capability/impl/FuelRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/FuelRecipeLogic.java
index f70ca3fcde9..26871a55d3c 100644
--- a/src/main/java/gregtech/api/capability/impl/FuelRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/FuelRecipeLogic.java
@@ -6,7 +6,7 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import org.jetbrains.annotations.NotNull;
@@ -40,7 +40,7 @@ protected boolean hasEnoughPower(long eut, int duration) {
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
standardOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(), getOverclockingVoltageFactor());
}
diff --git a/src/main/java/gregtech/api/capability/impl/HeatingCoilRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/HeatingCoilRecipeLogic.java
index 1c97891e9bb..fc9bd216d55 100644
--- a/src/main/java/gregtech/api/capability/impl/HeatingCoilRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/HeatingCoilRecipeLogic.java
@@ -5,8 +5,8 @@
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
import gregtech.api.recipes.logic.OverclockingLogic;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import org.jetbrains.annotations.NotNull;
@@ -26,18 +26,18 @@ public HeatingCoilRecipeLogic(RecipeMapMultiblockController metaTileEntity) {
}
@Override
- protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPre(ocParams, storage);
// coil EU/t discount
ocParams.setEut(OverclockingLogic.applyCoilEUtDiscount(ocParams.eut(),
((IHeatingCoil) metaTileEntity).getCurrentTemperature(),
- storage.getRecipePropertyValue(TemperatureProperty.getInstance(), 0)));
+ storage.get(TemperatureProperty.getInstance(), 0)));
}
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
heatingCoilOC(ocParams, ocResult, maxVoltage, ((IHeatingCoil) metaTileEntity).getCurrentTemperature(),
- propertyStorage.getRecipePropertyValue(TemperatureProperty.getInstance(), 0));
+ propertyStorage.get(TemperatureProperty.getInstance(), 0));
}
}
diff --git a/src/main/java/gregtech/api/capability/impl/MultiblockFuelRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/MultiblockFuelRecipeLogic.java
index 746593f366a..30c5e5410e3 100644
--- a/src/main/java/gregtech/api/capability/impl/MultiblockFuelRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/MultiblockFuelRecipeLogic.java
@@ -8,7 +8,7 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextFormattingUtil;
@@ -29,7 +29,7 @@ public MultiblockFuelRecipeLogic(RecipeMapMultiblockController tileEntity) {
}
@Override
- protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull RecipePropertyStorage storage) {
// apply maintenance bonuses
Tuple maintenanceValues = getMaintenanceValues();
@@ -40,7 +40,7 @@ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePr
}
@Override
- protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull RecipePropertyStorage storage) {
// apply maintenance penalties
Tuple maintenanceValues = getMaintenanceValues();
diff --git a/src/main/java/gregtech/api/capability/impl/MultiblockRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/MultiblockRecipeLogic.java
index 200f92ca873..ff95f0fbb0c 100644
--- a/src/main/java/gregtech/api/capability/impl/MultiblockRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/MultiblockRecipeLogic.java
@@ -12,7 +12,7 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.common.ConfigHolder;
@@ -281,7 +281,7 @@ protected boolean prepareRecipeDistinct(Recipe recipe) {
}
@Override
- protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPre(ocParams, storage);
// apply maintenance bonuses
@@ -295,13 +295,13 @@ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePr
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
subTickParallelOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(),
getOverclockingVoltageFactor());
}
@Override
- protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPost(ocResult, storage);
// apply maintenance penalties
diff --git a/src/main/java/gregtech/api/capability/impl/PrimitiveRecipeLogic.java b/src/main/java/gregtech/api/capability/impl/PrimitiveRecipeLogic.java
index d1893fa8f84..40e4f13ca43 100644
--- a/src/main/java/gregtech/api/capability/impl/PrimitiveRecipeLogic.java
+++ b/src/main/java/gregtech/api/capability/impl/PrimitiveRecipeLogic.java
@@ -5,7 +5,7 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import org.jetbrains.annotations.NotNull;
@@ -50,7 +50,7 @@ public long getMaxVoltage() {
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
ocParams.setEut(1L);
super.runOverclockingLogic(ocParams, ocResult, propertyStorage, maxVoltage);
}
diff --git a/src/main/java/gregtech/api/capability/impl/RecipeLogicEnergy.java b/src/main/java/gregtech/api/capability/impl/RecipeLogicEnergy.java
index 4e62346dcf2..8460b2a7aa7 100644
--- a/src/main/java/gregtech/api/capability/impl/RecipeLogicEnergy.java
+++ b/src/main/java/gregtech/api/capability/impl/RecipeLogicEnergy.java
@@ -5,7 +5,7 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import org.jetbrains.annotations.NotNull;
@@ -56,7 +56,7 @@ public long getMaxVoltage() {
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
subTickNonParallelOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(),
getOverclockingVoltageFactor());
}
diff --git a/src/main/java/gregtech/api/recipes/Recipe.java b/src/main/java/gregtech/api/recipes/Recipe.java
index 923c463e0c4..ff495651ac5 100644
--- a/src/main/java/gregtech/api/recipes/Recipe.java
+++ b/src/main/java/gregtech/api/recipes/Recipe.java
@@ -8,9 +8,9 @@
import gregtech.api.recipes.chance.output.impl.ChancedFluidOutput;
import gregtech.api.recipes.chance.output.impl.ChancedItemOutput;
import gregtech.api.recipes.ingredients.GTRecipeInput;
-import gregtech.api.recipes.recipeproperties.EmptyRecipePropertyStorage;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
-import gregtech.api.recipes.recipeproperties.RecipeProperty;
+import gregtech.api.recipes.properties.RecipeProperty;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorageImpl;
import gregtech.api.util.GTUtility;
import gregtech.api.util.ItemStackHashStrategy;
import gregtech.integration.groovy.GroovyScriptModule;
@@ -26,15 +26,15 @@
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
/**
* Class that represent machine recipe.
@@ -99,7 +99,7 @@ public static int getMaxChancedValue() {
// TODO YEET
private final boolean isCTRecipe;
private final boolean groovyRecipe;
- private final IRecipePropertyStorage recipePropertyStorage;
+ private final RecipePropertyStorage recipePropertyStorage;
private final int hashCode;
@@ -113,10 +113,9 @@ public Recipe(@NotNull List inputs,
long EUt,
boolean hidden,
boolean isCTRecipe,
- IRecipePropertyStorage recipePropertyStorage,
+ @NotNull RecipePropertyStorage recipePropertyStorage,
@NotNull GTRecipeCategory recipeCategory) {
- this.recipePropertyStorage = recipePropertyStorage == null ? EmptyRecipePropertyStorage.INSTANCE :
- recipePropertyStorage;
+ this.recipePropertyStorage = recipePropertyStorage;
this.inputs = GTRecipeInputCache.deduplicateInputs(inputs);
if (outputs.isEmpty()) {
this.outputs = Collections.emptyList();
@@ -742,40 +741,26 @@ public GTRecipeCategory getRecipeCategory() {
///////////////////////////////////////////////////////////
// Property Helper Methods //
///////////////////////////////////////////////////////////
- public T getProperty(RecipeProperty property, T defaultValue) {
- return recipePropertyStorage.getRecipePropertyValue(property, defaultValue);
- }
-
- public Object getPropertyRaw(String key) {
- return recipePropertyStorage.getRawRecipePropertyValue(key);
- }
-
- public Set, Object>> getPropertyValues() {
- return recipePropertyStorage.getRecipeProperties();
- }
-
- public Set getPropertyKeys() {
- return recipePropertyStorage.getRecipePropertyKeys();
- }
-
- public Set> getPropertyTypes() {
- return recipePropertyStorage.getPropertyTypes();
- }
- public boolean hasProperty(RecipeProperty> property) {
- return recipePropertyStorage.hasRecipeProperty(property);
- }
-
- public int getPropertyCount() {
- return recipePropertyStorage.getSize();
+ /**
+ * @see RecipePropertyStorageImpl#get(RecipeProperty, Object)
+ */
+ @Contract("_, !null -> !null")
+ public @Nullable T getProperty(@NotNull RecipeProperty property, @Nullable T defaultValue) {
+ return recipePropertyStorage.get(property, defaultValue);
}
- public int getUnhiddenPropertyCount() {
- return (int) recipePropertyStorage.getRecipeProperties().stream()
- .filter((property) -> !property.getKey().isHidden()).count();
+ /**
+ * @see RecipePropertyStorageImpl#contains(RecipeProperty)
+ */
+ public boolean hasProperty(@NotNull RecipeProperty> property) {
+ return recipePropertyStorage.contains(property);
}
- public IRecipePropertyStorage getRecipePropertyStorage() {
+ /**
+ * @return the property storage
+ */
+ public @NotNull RecipePropertyStorage propertyStorage() {
return recipePropertyStorage;
}
}
diff --git a/src/main/java/gregtech/api/recipes/RecipeBuilder.java b/src/main/java/gregtech/api/recipes/RecipeBuilder.java
index b57b8c25db4..0a6f07ee6e7 100644
--- a/src/main/java/gregtech/api/recipes/RecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/RecipeBuilder.java
@@ -16,11 +16,11 @@
import gregtech.api.recipes.ingredients.IntCircuitIngredient;
import gregtech.api.recipes.ingredients.nbtmatch.NBTCondition;
import gregtech.api.recipes.ingredients.nbtmatch.NBTMatcher;
-import gregtech.api.recipes.recipeproperties.CleanroomProperty;
-import gregtech.api.recipes.recipeproperties.DimensionProperty;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
-import gregtech.api.recipes.recipeproperties.RecipeProperty;
-import gregtech.api.recipes.recipeproperties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipeProperty;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorageImpl;
+import gregtech.api.recipes.properties.impl.CleanroomProperty;
+import gregtech.api.recipes.properties.impl.DimensionProperty;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.Material;
import gregtech.api.unification.ore.OrePrefix;
@@ -44,7 +44,6 @@
import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient;
import crafttweaker.CraftTweakerAPI;
import it.unimi.dsi.fastutil.ints.IntList;
-import it.unimi.dsi.fastutil.ints.IntLists;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
@@ -84,7 +83,7 @@ public class RecipeBuilder> {
protected boolean isCTRecipe = false;
protected int parallel = 0;
protected EnumValidationResult recipeStatus = EnumValidationResult.VALID;
- protected @Nullable IRecipePropertyStorage recipePropertyStorage = null;
+ protected RecipePropertyStorage recipePropertyStorage = RecipePropertyStorage.EMPTY;
protected boolean recipePropertyStorageErrored = false;
protected RecipeBuilder() {
@@ -108,10 +107,7 @@ public RecipeBuilder(Recipe recipe, RecipeMap recipeMap) {
this.EUt = recipe.getEUt();
this.hidden = recipe.isHidden();
this.category = recipe.getRecipeCategory();
- this.recipePropertyStorage = recipe.getRecipePropertyStorage().copy();
- if (this.recipePropertyStorage != null) {
- this.recipePropertyStorage.freeze(false);
- }
+ this.recipePropertyStorage = recipe.propertyStorage().copy();
}
@SuppressWarnings("CopyConstructorMissesField")
@@ -129,11 +125,7 @@ protected RecipeBuilder(RecipeBuilder recipeBuilder) {
this.EUt = recipeBuilder.EUt;
this.hidden = recipeBuilder.hidden;
this.category = recipeBuilder.category;
- this.recipePropertyStorage = recipeBuilder.recipePropertyStorage == null ? null :
- recipeBuilder.recipePropertyStorage.copy();
- if (this.recipePropertyStorage != null) {
- this.recipePropertyStorage = this.recipePropertyStorage.copy();
- }
+ this.recipePropertyStorage = recipeBuilder.recipePropertyStorage.copy();
}
public R cleanroom(@Nullable CleanroomType cleanroom) {
@@ -150,7 +142,7 @@ public R dimension(int dimensionID) {
public R dimension(int dimensionID, boolean toBlackList) {
DimensionProperty.DimensionPropertyList dimensionIDs = getCompleteDimensionIDs();
- if (dimensionIDs == DimensionProperty.DimensionPropertyList.EMPTY_LIST) {
+ if (dimensionIDs == null) {
dimensionIDs = new DimensionProperty.DimensionPropertyList();
this.applyProperty(DimensionProperty.getInstance(), dimensionIDs);
}
@@ -158,29 +150,26 @@ public R dimension(int dimensionID, boolean toBlackList) {
return (R) this;
}
- public DimensionProperty.DimensionPropertyList getCompleteDimensionIDs() {
- return this.recipePropertyStorage == null ? DimensionProperty.DimensionPropertyList.EMPTY_LIST :
- this.recipePropertyStorage.getRecipePropertyValue(DimensionProperty.getInstance(),
- DimensionProperty.DimensionPropertyList.EMPTY_LIST);
+ public @Nullable DimensionProperty.DimensionPropertyList getCompleteDimensionIDs() {
+ return this.recipePropertyStorage.get(DimensionProperty.getInstance(), null);
}
- public IntList getDimensionIDs() {
- return this.recipePropertyStorage == null ? IntLists.EMPTY_LIST :
- this.recipePropertyStorage.getRecipePropertyValue(DimensionProperty.getInstance(),
- DimensionProperty.DimensionPropertyList.EMPTY_LIST).whiteListDimensions;
+ public @NotNull IntList getDimensionIDs() {
+ return this.recipePropertyStorage.get(DimensionProperty.getInstance(),
+ DimensionProperty.DimensionPropertyList.EMPTY_LIST).whiteListDimensions;
}
- public IntList getBlockedDimensionIDs() {
- return this.recipePropertyStorage == null ? IntLists.EMPTY_LIST :
- this.recipePropertyStorage.getRecipePropertyValue(DimensionProperty.getInstance(),
- DimensionProperty.DimensionPropertyList.EMPTY_LIST).whiteListDimensions;
+ public @NotNull IntList getBlockedDimensionIDs() {
+ return this.recipePropertyStorage.get(DimensionProperty.getInstance(),
+ DimensionProperty.DimensionPropertyList.EMPTY_LIST).blackListDimensions;
}
- public boolean applyProperty(@NotNull String key, @Nullable Object value) {
+ @MustBeInvokedByOverriders
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(DimensionProperty.KEY)) {
if (value instanceof DimensionProperty.DimensionPropertyList list) {
DimensionProperty.DimensionPropertyList dimensionIDs = getCompleteDimensionIDs();
- if (dimensionIDs == DimensionProperty.DimensionPropertyList.EMPTY_LIST) {
+ if (dimensionIDs == null) {
dimensionIDs = new DimensionProperty.DimensionPropertyList();
this.applyProperty(DimensionProperty.getInstance(), dimensionIDs);
}
@@ -201,22 +190,16 @@ public boolean applyProperty(@NotNull String key, @Nullable Object value) {
return false;
}
- public boolean applyProperty(@NotNull RecipeProperty> property, @Nullable Object value) {
- if (value == null) {
- if (this.recipePropertyStorage != null) {
- return this.recipePropertyStorage.remove(property);
- }
- } else {
- if (this.recipePropertyStorage == null) {
- this.recipePropertyStorage = new RecipePropertyStorage();
- }
- boolean stored = this.recipePropertyStorage.store(property, value);
- if (!stored) {
- this.recipePropertyStorageErrored = true;
- }
- return stored;
+ public final boolean applyProperty(@NotNull RecipeProperty> property, @NotNull Object value) {
+ if (this.recipePropertyStorage == RecipePropertyStorage.EMPTY) {
+ this.recipePropertyStorage = new RecipePropertyStorageImpl();
+ }
+
+ boolean stored = this.recipePropertyStorage.store(property, value);
+ if (!stored) {
+ this.recipePropertyStorageErrored = true;
}
- return true;
+ return stored;
}
public R input(GTRecipeInput input) {
@@ -791,8 +774,8 @@ public void chancedOutputsMultiply(Recipe chancedOutputsFrom, int numberOfOperat
*/
public R append(Recipe recipe, int multiplier, boolean multiplyDuration) {
- for (Map.Entry, Object> property : recipe.getPropertyValues()) {
- this.applyProperty(property.getKey().getKey(), property.getValue());
+ for (Map.Entry, Object> property : recipe.propertyStorage().entrySet()) {
+ this.applyPropertyCT(property.getKey().getKey(), property.getValue());
}
// Create holders for the various parts of the new multiplied Recipe
@@ -905,12 +888,9 @@ public R copy() {
return (R) new RecipeBuilder<>(this);
}
- protected EnumValidationResult finalizeAndValidate() {
- return recipePropertyStorageErrored ? EnumValidationResult.INVALID : validate();
- }
-
public ValidationResult build() {
- return ValidationResult.newResult(finalizeAndValidate(), new Recipe(inputs, outputs,
+ EnumValidationResult result = recipePropertyStorageErrored ? EnumValidationResult.INVALID : validate();
+ return ValidationResult.newResult(result, new Recipe(inputs, outputs,
new ChancedOutputList<>(this.chancedOutputLogic, chancedOutputs),
fluidInputs, fluidOutputs,
new ChancedOutputList<>(this.chancedFluidOutputLogic, chancedFluidOutputs),
@@ -956,9 +936,6 @@ protected EnumValidationResult validate() {
if (recipeStatus == EnumValidationResult.INVALID) {
GTLog.logger.error("Invalid recipe, read the errors above: {}", this);
}
- if (recipePropertyStorage != null) {
- recipePropertyStorage.freeze(true);
- }
return recipeStatus;
}
@@ -1067,10 +1044,8 @@ public int getDuration() {
return duration;
}
- @Nullable
- public CleanroomType getCleanroom() {
- return this.recipePropertyStorage == null ? null :
- this.recipePropertyStorage.getRecipePropertyValue(CleanroomProperty.getInstance(), null);
+ public @Nullable CleanroomType getCleanroom() {
+ return this.recipePropertyStorage.get(CleanroomProperty.getInstance(), null);
}
@Override
diff --git a/src/main/java/gregtech/api/recipes/builders/AssemblyLineRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/AssemblyLineRecipeBuilder.java
index 40a23a261ff..dc711dd0a0a 100644
--- a/src/main/java/gregtech/api/recipes/builders/AssemblyLineRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/AssemblyLineRecipeBuilder.java
@@ -4,8 +4,8 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.ResearchProperty;
-import gregtech.api.recipes.recipeproperties.ResearchPropertyData;
+import gregtech.api.recipes.properties.impl.ResearchProperty;
+import gregtech.api.recipes.properties.impl.ResearchPropertyData;
import gregtech.api.util.AssemblyLineManager;
import gregtech.api.util.EnumValidationResult;
import gregtech.api.util.GTLog;
@@ -14,7 +14,6 @@
import net.minecraft.item.ItemStack;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -45,14 +44,15 @@ public AssemblyLineRecipeBuilder copy() {
}
@Override
- public boolean applyProperty(@NotNull String key, @Nullable Object value) {
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(ResearchProperty.KEY)) {
if (value instanceof ItemStack itemStack) {
scannerResearch(itemStack);
return true;
}
+ return false;
}
- return super.applyProperty(key, value);
+ return super.applyPropertyCT(key, value);
}
private boolean applyResearchProperty(ResearchPropertyData.ResearchEntry researchEntry) {
@@ -70,15 +70,13 @@ private boolean applyResearchProperty(ResearchPropertyData.ResearchEntry researc
return false;
}
- if (recipePropertyStorage != null && recipePropertyStorage.hasRecipeProperty(ResearchProperty.getInstance())) {
- ResearchPropertyData property = recipePropertyStorage.getRecipePropertyValue(ResearchProperty.getInstance(),
- null);
- if (property == null) throw new IllegalStateException("Property storage has a null property");
+ ResearchPropertyData property = recipePropertyStorage.get(ResearchProperty.getInstance(), null);
+ if (property != null) {
property.add(researchEntry);
return true;
}
- ResearchPropertyData property = new ResearchPropertyData();
+ property = new ResearchPropertyData();
if (applyProperty(ResearchProperty.getInstance(), property)) {
property.add(researchEntry);
return true;
diff --git a/src/main/java/gregtech/api/recipes/builders/BlastRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/BlastRecipeBuilder.java
index 8aa2bd236cc..c5bf92c5e16 100644
--- a/src/main/java/gregtech/api/recipes/builders/BlastRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/BlastRecipeBuilder.java
@@ -3,7 +3,7 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import gregtech.api.util.EnumValidationResult;
import gregtech.api.util.GTLog;
@@ -28,12 +28,12 @@ public BlastRecipeBuilder copy() {
}
@Override
- public boolean applyProperty(@NotNull String key, Object value) {
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(TemperatureProperty.KEY)) {
this.blastFurnaceTemp(((Number) value).intValue());
return true;
}
- return super.applyProperty(key, value);
+ return super.applyPropertyCT(key, value);
}
public BlastRecipeBuilder blastFurnaceTemp(int blastFurnaceTemp) {
@@ -47,8 +47,7 @@ public BlastRecipeBuilder blastFurnaceTemp(int blastFurnaceTemp) {
}
public int getBlastFurnaceTemp() {
- return this.recipePropertyStorage == null ? 0 :
- this.recipePropertyStorage.getRecipePropertyValue(TemperatureProperty.getInstance(), 0);
+ return this.recipePropertyStorage.get(TemperatureProperty.getInstance(), 0);
}
@Override
diff --git a/src/main/java/gregtech/api/recipes/builders/ComputationRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/ComputationRecipeBuilder.java
index 2da0309972a..1d6c49a75d8 100644
--- a/src/main/java/gregtech/api/recipes/builders/ComputationRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/ComputationRecipeBuilder.java
@@ -3,8 +3,8 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.ComputationProperty;
-import gregtech.api.recipes.recipeproperties.TotalComputationProperty;
+import gregtech.api.recipes.properties.impl.ComputationProperty;
+import gregtech.api.recipes.properties.impl.TotalComputationProperty;
import gregtech.api.util.EnumValidationResult;
import gregtech.api.util.GTLog;
@@ -28,7 +28,7 @@ public ComputationRecipeBuilder copy() {
}
@Override
- public boolean applyProperty(@NotNull String key, Object value) {
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(ComputationProperty.KEY)) {
this.CWUt(((Number) value).intValue());
return true;
@@ -37,7 +37,7 @@ public boolean applyProperty(@NotNull String key, Object value) {
this.totalCWU(((Number) value).intValue());
return true;
}
- return super.applyProperty(key, value);
+ return super.applyPropertyCT(key, value);
}
public ComputationRecipeBuilder CWUt(int cwut) {
diff --git a/src/main/java/gregtech/api/recipes/builders/FusionRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/FusionRecipeBuilder.java
index a6f56e1420a..91622a9950c 100644
--- a/src/main/java/gregtech/api/recipes/builders/FusionRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/FusionRecipeBuilder.java
@@ -3,7 +3,7 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty;
+import gregtech.api.recipes.properties.impl.FusionEUToStartProperty;
import gregtech.api.util.EnumValidationResult;
import gregtech.api.util.GTLog;
@@ -28,12 +28,12 @@ public FusionRecipeBuilder copy() {
}
@Override
- public boolean applyProperty(@NotNull String key, Object value) {
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(FusionEUToStartProperty.KEY)) {
this.EUToStart(((Number) value).longValue());
return true;
}
- return super.applyProperty(key, value);
+ return super.applyPropertyCT(key, value);
}
public FusionRecipeBuilder EUToStart(long EUToStart) {
@@ -46,8 +46,7 @@ public FusionRecipeBuilder EUToStart(long EUToStart) {
}
public long getEUToStart() {
- return this.recipePropertyStorage == null ? 0L :
- this.recipePropertyStorage.getRecipePropertyValue(FusionEUToStartProperty.getInstance(), 0L);
+ return this.recipePropertyStorage.get(FusionEUToStartProperty.getInstance(), 0L);
}
@Override
diff --git a/src/main/java/gregtech/api/recipes/builders/ImplosionRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/ImplosionRecipeBuilder.java
index 3ada0e83415..ce078b9751b 100644
--- a/src/main/java/gregtech/api/recipes/builders/ImplosionRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/ImplosionRecipeBuilder.java
@@ -4,10 +4,9 @@
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.ingredients.GTRecipeItemInput;
-import gregtech.api.recipes.recipeproperties.ImplosionExplosiveProperty;
+import gregtech.api.recipes.properties.impl.ImplosionExplosiveProperty;
import gregtech.api.util.EnumValidationResult;
import gregtech.api.util.GTLog;
-import gregtech.api.util.ValidationResult;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
@@ -34,61 +33,52 @@ public ImplosionRecipeBuilder copy() {
}
@Override
- public boolean applyProperty(@NotNull String key, Object value) {
+ public boolean applyPropertyCT(@NotNull String key, @NotNull Object value) {
if (key.equals(ImplosionExplosiveProperty.KEY)) {
- if (value instanceof ItemStack) {
- this.applyProperty(ImplosionExplosiveProperty.getInstance(), value);
- } else {
- this.applyProperty(ImplosionExplosiveProperty.getInstance(), new ItemStack(Blocks.TNT, (int) value));
+ if (value instanceof ItemStack stack) {
+ return this.applyProperty(ImplosionExplosiveProperty.getInstance(), stack);
+ } else if (value instanceof Number number) {
+ return this.applyProperty(ImplosionExplosiveProperty.getInstance(), number.intValue());
}
- return true;
+ return false;
}
- return super.applyProperty(key, value);
+ return super.applyPropertyCT(key, value);
}
@ZenMethod
- public ImplosionRecipeBuilder explosivesAmount(int explosivesAmount) {
- if (1 > explosivesAmount || explosivesAmount > 64) {
- GTLog.logger.error("Amount of explosives should be from 1 to 64 inclusive", new Throwable());
- recipeStatus = EnumValidationResult.INVALID;
- }
- this.applyProperty(ImplosionExplosiveProperty.getInstance(), new ItemStack(Blocks.TNT, explosivesAmount));
- return this;
+ public ImplosionRecipeBuilder explosives(int amount) {
+ return explosives(new ItemStack(Blocks.TNT, amount));
}
@ZenMethod
- public ImplosionRecipeBuilder explosivesType(ItemStack explosivesType) {
- if (1 > explosivesType.getCount() || explosivesType.getCount() > 64) {
+ public ImplosionRecipeBuilder explosives(@NotNull ItemStack explosive) {
+ if (explosive.isEmpty()) {
+ GTLog.logger.error("Cannot use empty explosives", new Throwable());
+ this.recipeStatus = EnumValidationResult.INVALID;
+ return this;
+ }
+
+ int count = explosive.getCount();
+ if (count < 1 || count > 64) {
GTLog.logger.error("Amount of explosives should be from 1 to 64 inclusive", new Throwable());
recipeStatus = EnumValidationResult.INVALID;
+ return this;
}
- this.applyProperty(ImplosionExplosiveProperty.getInstance(), explosivesType);
- return this;
- }
-
- public ItemStack getExplosivesType() {
- if (this.recipePropertyStorage == null) {
- return ItemStack.EMPTY;
+ if (this.applyProperty(ImplosionExplosiveProperty.getInstance(), explosive)) {
+ this.inputs.add(new GTRecipeItemInput(explosive));
}
- return this.recipePropertyStorage.getRecipePropertyValue(ImplosionExplosiveProperty.getInstance(),
- ItemStack.EMPTY);
+ return this;
}
- public ValidationResult build() {
- ItemStack explosivesType = getExplosivesType();
- if (!explosivesType.isEmpty()) {
- this.inputs.add(new GTRecipeItemInput(explosivesType));
- } else {
- this.recipePropertyStorageErrored = true;
- }
- return super.build();
+ public @NotNull ItemStack getExplosives() {
+ return this.recipePropertyStorage.get(ImplosionExplosiveProperty.getInstance(), ItemStack.EMPTY);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.appendSuper(super.toString())
- .append(ImplosionExplosiveProperty.getInstance().getKey(), getExplosivesType())
+ .append(ImplosionExplosiveProperty.getInstance().getKey(), getExplosives())
.toString();
}
}
diff --git a/src/main/java/gregtech/api/recipes/builders/PrimitiveRecipeBuilder.java b/src/main/java/gregtech/api/recipes/builders/PrimitiveRecipeBuilder.java
index 858a94d1177..ec0e8cf2202 100644
--- a/src/main/java/gregtech/api/recipes/builders/PrimitiveRecipeBuilder.java
+++ b/src/main/java/gregtech/api/recipes/builders/PrimitiveRecipeBuilder.java
@@ -3,7 +3,7 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.PrimitiveProperty;
+import gregtech.api.recipes.properties.impl.PrimitiveProperty;
import gregtech.api.util.ValidationResult;
public class PrimitiveRecipeBuilder extends RecipeBuilder {
diff --git a/src/main/java/gregtech/api/recipes/machines/RecipeMapAssemblyLine.java b/src/main/java/gregtech/api/recipes/machines/RecipeMapAssemblyLine.java
index 5c23b88f6a2..d1d8301a3c7 100644
--- a/src/main/java/gregtech/api/recipes/machines/RecipeMapAssemblyLine.java
+++ b/src/main/java/gregtech/api/recipes/machines/RecipeMapAssemblyLine.java
@@ -3,8 +3,8 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.ResearchProperty;
-import gregtech.api.recipes.recipeproperties.ResearchPropertyData;
+import gregtech.api.recipes.properties.impl.ResearchProperty;
+import gregtech.api.recipes.properties.impl.ResearchPropertyData;
import gregtech.api.recipes.ui.RecipeMapUIFunction;
import gregtech.core.sound.GTSoundEvents;
@@ -32,15 +32,11 @@ public RecipeMapAssemblyLine(@NotNull String unlocalizedName, @NotNull R default
@Override
public boolean compileRecipe(Recipe recipe) {
if (!super.compileRecipe(recipe)) return false;
- if (recipe.hasProperty(ResearchProperty.getInstance())) {
- ResearchPropertyData data = recipe.getProperty(ResearchProperty.getInstance(), null);
- if (data != null) {
- for (ResearchPropertyData.ResearchEntry entry : data) {
- addDataStickEntry(entry.getResearchId(), recipe);
- }
- return true;
+ ResearchPropertyData data = recipe.getProperty(ResearchProperty.getInstance(), null);
+ if (data != null) {
+ for (ResearchPropertyData.ResearchEntry entry : data) {
+ addDataStickEntry(entry.researchId(), recipe);
}
- return false;
}
return true;
}
@@ -48,15 +44,11 @@ public boolean compileRecipe(Recipe recipe) {
@Override
public boolean removeRecipe(@NotNull Recipe recipe) {
if (!super.removeRecipe(recipe)) return false;
- if (recipe.hasProperty(ResearchProperty.getInstance())) {
- ResearchPropertyData data = recipe.getProperty(ResearchProperty.getInstance(), null);
- if (data != null) {
- for (ResearchPropertyData.ResearchEntry entry : data) {
- removeDataStickEntry(entry.getResearchId(), recipe);
- }
- return true;
+ ResearchPropertyData data = recipe.getProperty(ResearchProperty.getInstance(), null);
+ if (data != null) {
+ for (ResearchPropertyData.ResearchEntry entry : data) {
+ removeDataStickEntry(entry.researchId(), recipe);
}
- return false;
}
return true;
}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/RecipeProperty.java b/src/main/java/gregtech/api/recipes/properties/RecipeProperty.java
similarity index 62%
rename from src/main/java/gregtech/api/recipes/recipeproperties/RecipeProperty.java
rename to src/main/java/gregtech/api/recipes/properties/RecipeProperty.java
index 9dde81bb195..bb54c07603f 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/RecipeProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/RecipeProperty.java
@@ -1,11 +1,13 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties;
import net.minecraft.client.Minecraft;
+import net.minecraft.nbt.NBTBase;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import org.jetbrains.annotations.NotNull;
+
import java.util.List;
-import java.util.Objects;
public abstract class RecipeProperty {
@@ -17,6 +19,18 @@ protected RecipeProperty(String key, Class type) {
this.type = type;
}
+ /**
+ * @param value the value to serialize
+ * @return the serialized form of the value
+ */
+ public abstract @NotNull NBTBase serialize(@NotNull Object value);
+
+ /**
+ * @param nbt the nbt to deserialize
+ * @return the deserialized property value
+ */
+ public abstract @NotNull Object deserialize(@NotNull NBTBase nbt);
+
@SideOnly(Side.CLIENT)
public abstract void drawInfo(Minecraft minecraft, int x, int y, int color, Object value);
@@ -28,19 +42,15 @@ public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value,
@SideOnly(Side.CLIENT)
public void getTooltipStrings(List tooltip, int mouseX, int mouseY, Object value) {}
- public int getInfoHeight(Object value) {
+ public int getInfoHeight(@NotNull Object value) {
return 10; // GTRecipeWrapper#LINE_HEIGHT
}
- public boolean isOfType(Class> otherType) {
- return this.type == otherType;
- }
-
- public String getKey() {
+ public final @NotNull String getKey() {
return key;
}
- public T castValue(Object value) {
+ protected final T castValue(@NotNull Object value) {
return this.type.cast(value);
}
@@ -75,15 +85,20 @@ public boolean hideDuration() {
}
@Override
- public boolean equals(Object o) {
+ public final boolean equals(Object o) {
if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- RecipeProperty> that = (RecipeProperty>) o;
- return Objects.equals(type, that.type) && Objects.equals(key, that.key);
+ if (!(o instanceof RecipeProperty>that)) return false;
+
+ return type.equals(that.type) && getKey().equals(that.getKey());
+ }
+
+ @Override
+ public final int hashCode() {
+ return 31 * type.hashCode() + getKey().hashCode();
}
@Override
- public int hashCode() {
- return Objects.hash(type, key);
+ public String toString() {
+ return "RecipeProperty{" + "key='" + key + "'}";
}
}
diff --git a/src/main/java/gregtech/api/recipes/properties/RecipePropertyRegistry.java b/src/main/java/gregtech/api/recipes/properties/RecipePropertyRegistry.java
new file mode 100644
index 00000000000..13defc9f723
--- /dev/null
+++ b/src/main/java/gregtech/api/recipes/properties/RecipePropertyRegistry.java
@@ -0,0 +1,29 @@
+package gregtech.api.recipes.properties;
+
+import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+public final class RecipePropertyRegistry {
+
+ private final Map> map = new Object2ReferenceOpenHashMap<>();
+
+ /**
+ * @param key the RecipeProperty's key
+ * @param property the property's instance
+ */
+ public void register(@NotNull String key, @NotNull RecipeProperty> property) {
+ if (map.containsKey(key)) {
+ throw new IllegalArgumentException("RecipeProperty is already registered: " + key);
+ }
+ map.put(key, property);
+ }
+
+ @ApiStatus.Internal
+ public @Nullable RecipeProperty> get(@NotNull String key) {
+ return map.get(key);
+ }
+}
diff --git a/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorage.java b/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorage.java
new file mode 100644
index 00000000000..790143293dd
--- /dev/null
+++ b/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorage.java
@@ -0,0 +1,119 @@
+package gregtech.api.recipes.properties;
+
+import gregtech.api.util.GTLog;
+
+import net.minecraft.nbt.NBTTagCompound;
+
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.UnmodifiableView;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+public interface RecipePropertyStorage {
+
+ /**
+ * @param recipeProperty the property to store
+ * @param value the value to store
+ * @return if the store succeeds
+ */
+ boolean store(@NotNull RecipeProperty> recipeProperty, @NotNull Object value);
+
+ /**
+ * @return a copy of this property storage
+ */
+ @NotNull
+ RecipePropertyStorage copy();
+
+ /**
+ * @return number of stored properties
+ */
+ int size();
+
+ /**
+ * @return all stored properties and values
+ */
+ @NotNull
+ Set, Object>> entrySet();
+
+ /**
+ * @param recipeProperty the property to retrieve
+ * @param defaultValue default value if the property is not found
+ * @param the type of returned value
+ * @return value associated with the provided recipeProperty, otherwise the default
+ */
+ @Contract("_, !null -> !null")
+ @Nullable T get(@NotNull RecipeProperty recipeProperty, @Nullable T defaultValue);
+
+ /**
+ * @param recipeProperty the property to check
+ * @return if the property is in this storage
+ */
+ boolean contains(@NotNull RecipeProperty> recipeProperty);
+
+ /**
+ * @return the recipe property values
+ */
+ @UnmodifiableView
+ @NotNull
+ Set<@NotNull RecipeProperty>> values();
+
+ @NotNull
+ NBTTagCompound serializeNBT();
+
+ void deserializeNBT(@NotNull NBTTagCompound nbt);
+
+ RecipePropertyStorage EMPTY = new RecipePropertyStorage() {
+
+ @Override
+ public boolean store(@NotNull RecipeProperty> recipeProperty, @NotNull Object value) {
+ throw new UnsupportedOperationException("empty");
+ }
+
+ @Override
+ public @NotNull RecipePropertyStorage copy() {
+ return this;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public @NotNull Set, Object>> entrySet() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public @Nullable T get(@NotNull RecipeProperty recipeProperty, @Nullable T defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public boolean contains(@NotNull RecipeProperty> recipeProperty) {
+ return false;
+ }
+
+ @Override
+ public @UnmodifiableView @NotNull Set<@NotNull RecipeProperty>> values() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public @NotNull NBTTagCompound serializeNBT() {
+ return new NBTTagCompound();
+ }
+
+ @Override
+ public void deserializeNBT(@NotNull NBTTagCompound nbt) {
+ if (!nbt.isEmpty()) {
+ GTLog.logger.warn("Tried to deserialize non-empty tag in RecipePropertyStorage.EMPTY: {}", nbt,
+ new Throwable());
+ }
+ }
+ };
+}
diff --git a/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorageImpl.java b/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorageImpl.java
new file mode 100644
index 00000000000..ffc7ea21227
--- /dev/null
+++ b/src/main/java/gregtech/api/recipes/properties/RecipePropertyStorageImpl.java
@@ -0,0 +1,111 @@
+package gregtech.api.recipes.properties;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.util.GTLog;
+
+import net.minecraft.nbt.NBTTagCompound;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.UnmodifiableView;
+
+import java.util.Map;
+import java.util.Set;
+
+public final class RecipePropertyStorageImpl implements RecipePropertyStorage {
+
+ private final Map, Object> map;
+
+ public RecipePropertyStorageImpl() {
+ this(new Object2ObjectArrayMap<>(1));
+ }
+
+ private RecipePropertyStorageImpl(@NotNull Map, Object> map) {
+ this.map = map;
+ }
+
+ @Override
+ public boolean store(@NotNull RecipeProperty> recipeProperty, @NotNull Object value) {
+ String key = recipeProperty.getKey();
+ if (map.containsKey(recipeProperty)) {
+ GTLog.logger.warn("Duplicate recipe property added: {} -> {}", key, value, new Throwable());
+ return false;
+ }
+
+ try {
+ recipeProperty.castValue(value);
+ } catch (ClassCastException e) {
+ GTLog.logger.error("Provided incorrect value for RecipeProperty with key {}", key, e);
+ return false;
+ }
+
+ map.put(recipeProperty, value);
+ return true;
+ }
+
+ @Override
+ public @NotNull RecipePropertyStorage copy() {
+ return new RecipePropertyStorageImpl(new Object2ObjectArrayMap<>(this.map));
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public @NotNull Set, Object>> entrySet() {
+ return this.map.entrySet();
+ }
+
+ @Override
+ @Contract("_, !null -> !null")
+ public @Nullable T get(@NotNull RecipeProperty recipeProperty, @Nullable T defaultValue) {
+ var value = map.get(recipeProperty);
+ if (value == null) {
+ return defaultValue;
+ }
+
+ return recipeProperty.castValue(value);
+ }
+
+ @Override
+ public boolean contains(@NotNull RecipeProperty> recipeProperty) {
+ return map.containsKey(recipeProperty);
+ }
+
+ @Override
+ @UnmodifiableView
+ public @NotNull Set<@NotNull RecipeProperty>> values() {
+ return map.keySet();
+ }
+
+ @Override
+ public @NotNull String toString() {
+ return "RecipePropertyStorage{" + map + '}';
+ }
+
+ @Override
+ public @NotNull NBTTagCompound serializeNBT() {
+ NBTTagCompound tag = new NBTTagCompound();
+ for (var entry : map.entrySet()) {
+ var property = entry.getKey();
+ tag.setTag(property.getKey(), property.serialize(entry.getValue()));
+ }
+ return tag;
+ }
+
+ @Override
+ public void deserializeNBT(@NotNull NBTTagCompound nbt) {
+ for (var entry : nbt.tagMap.entrySet()) {
+ var property = GregTechAPI.RECIPE_PROPERTIES.get(entry.getKey());
+ if (property == null) {
+ GTLog.logger.warn("Failed to read property with key {}", entry.getKey());
+ continue;
+ }
+ map.put(property, property.deserialize(entry.getValue()));
+ }
+ }
+}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/CleanroomProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/CleanroomProperty.java
similarity index 63%
rename from src/main/java/gregtech/api/recipes/recipeproperties/CleanroomProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/CleanroomProperty.java
index e048ffa5626..5329b868c04 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/CleanroomProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/CleanroomProperty.java
@@ -1,15 +1,21 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+import gregtech.api.GregTechAPI;
import gregtech.api.metatileentity.multiblock.CleanroomType;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagString;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.jetbrains.annotations.NotNull;
-public class CleanroomProperty extends RecipeProperty {
+import java.util.Objects;
+
+public final class CleanroomProperty extends RecipeProperty {
public static final String KEY = "cleanroom";
@@ -22,24 +28,27 @@ private CleanroomProperty() {
public static CleanroomProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new CleanroomProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
@Override
- @SideOnly(Side.CLIENT)
- public void drawInfo(@NotNull Minecraft minecraft, int x, int y, int color, Object value) {
- CleanroomType type = castValue(value);
- if (type == null) return;
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagString(castValue(value).getName());
+ }
- minecraft.fontRenderer.drawString(I18n.format("gregtech.recipe.cleanroom", getName(type)), x, y, color);
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return Objects.requireNonNull(CleanroomType.getByName(((NBTTagString) nbt).getString()));
}
@Override
- public int getInfoHeight(Object value) {
+ @SideOnly(Side.CLIENT)
+ public void drawInfo(@NotNull Minecraft minecraft, int x, int y, int color, Object value) {
CleanroomType type = castValue(value);
- if (type == null) return 0;
- return super.getInfoHeight(value);
+
+ minecraft.fontRenderer.drawString(I18n.format("gregtech.recipe.cleanroom", getName(type)), x, y, color);
}
@NotNull
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/ComputationProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/ComputationProperty.java
similarity index 53%
rename from src/main/java/gregtech/api/recipes/recipeproperties/ComputationProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/ComputationProperty.java
index 5f2de1b653b..f57a6ed2ea7 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/ComputationProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/ComputationProperty.java
@@ -1,27 +1,45 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagInt;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
-public class ComputationProperty extends RecipeProperty {
+import org.jetbrains.annotations.NotNull;
+
+public final class ComputationProperty extends RecipeProperty {
public static final String KEY = "computation_per_tick";
private static ComputationProperty INSTANCE;
- protected ComputationProperty() {
+ private ComputationProperty() {
super(KEY, Integer.class);
}
public static ComputationProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new ComputationProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagInt(castValue(value));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagInt) nbt).getInt();
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/DimensionProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/DimensionProperty.java
similarity index 63%
rename from src/main/java/gregtech/api/recipes/recipeproperties/DimensionProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/DimensionProperty.java
index 3795db18aa1..721300af5d4 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/DimensionProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/DimensionProperty.java
@@ -1,17 +1,22 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import gregtech.api.worldgen.config.WorldGenRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
+import org.jetbrains.annotations.NotNull;
-public class DimensionProperty extends RecipeProperty {
+public final class DimensionProperty extends RecipeProperty {
public static final String KEY = "dimension";
@@ -22,11 +27,36 @@ private DimensionProperty() {
}
public static DimensionProperty getInstance() {
- if (INSTANCE == null)
+ if (INSTANCE == null) {
INSTANCE = new DimensionProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
+ }
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ DimensionPropertyList list = castValue(value);
+ NBTTagCompound tag = new NBTTagCompound();
+ tag.setIntArray("whiteListDimensions", list.whiteListDimensions.toArray(new int[0]));
+ tag.setIntArray("blackListDimensions", list.blackListDimensions.toArray(new int[0]));
+ return tag;
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ NBTTagCompound tag = (NBTTagCompound) nbt;
+ DimensionPropertyList list = new DimensionPropertyList();
+ for (int i : tag.getIntArray("whiteListDimensions")) {
+ list.add(i, false);
+ }
+
+ for (int i : tag.getIntArray("blackListDimensions")) {
+ list.add(i, true);
+ }
+ return tag;
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
@@ -62,8 +92,8 @@ public static class DimensionPropertyList {
public static DimensionPropertyList EMPTY_LIST = new DimensionPropertyList();
- public IntList whiteListDimensions = new IntArrayList();
- public IntList blackListDimensions = new IntArrayList();
+ public final IntList whiteListDimensions = new IntArrayList();
+ public final IntList blackListDimensions = new IntArrayList();
public void add(int key, boolean toBlacklist) {
if (toBlacklist) {
@@ -75,16 +105,13 @@ public void add(int key, boolean toBlacklist) {
}
}
- public void merge(DimensionPropertyList list) {
+ public void merge(@NotNull DimensionPropertyList list) {
this.whiteListDimensions.addAll(list.whiteListDimensions);
this.blackListDimensions.addAll(list.blackListDimensions);
}
public boolean checkDimension(int dim) {
- boolean valid = true;
- if (this.blackListDimensions.size() > 0) valid = !this.blackListDimensions.contains(dim);
- if (this.whiteListDimensions.size() > 0) valid = this.whiteListDimensions.contains(dim);
- return valid;
+ return !blackListDimensions.contains(dim) && whiteListDimensions.contains(dim);
}
}
}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/FusionEUToStartProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/FusionEUToStartProperty.java
similarity index 74%
rename from src/main/java/gregtech/api/recipes/recipeproperties/FusionEUToStartProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/FusionEUToStartProperty.java
index 758480a4816..13446abe8d1 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/FusionEUToStartProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/FusionEUToStartProperty.java
@@ -1,19 +1,24 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import gregtech.api.util.TextFormattingUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagLong;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
+import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.TreeMap;
-public class FusionEUToStartProperty extends RecipeProperty {
+public final class FusionEUToStartProperty extends RecipeProperty {
public static final String KEY = "eu_to_start";
@@ -21,18 +26,29 @@ public class FusionEUToStartProperty extends RecipeProperty {
private static FusionEUToStartProperty INSTANCE;
- protected FusionEUToStartProperty() {
+ private FusionEUToStartProperty() {
super(KEY, Long.class);
}
public static FusionEUToStartProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new FusionEUToStartProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagLong(castValue(value));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagLong) nbt).getLong();
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/ImplosionExplosiveProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/ImplosionExplosiveProperty.java
similarity index 55%
rename from src/main/java/gregtech/api/recipes/recipeproperties/ImplosionExplosiveProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/ImplosionExplosiveProperty.java
index fd88401041b..915fc5aa4e3 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/ImplosionExplosiveProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/ImplosionExplosiveProperty.java
@@ -1,12 +1,19 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
-public class ImplosionExplosiveProperty extends RecipeProperty {
+import org.jetbrains.annotations.NotNull;
+
+public final class ImplosionExplosiveProperty extends RecipeProperty {
public static final String KEY = "explosives";
@@ -19,16 +26,27 @@ private ImplosionExplosiveProperty() {
public static ImplosionExplosiveProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new ImplosionExplosiveProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return castValue(value).serializeNBT();
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return new ItemStack((NBTTagCompound) nbt);
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
minecraft.fontRenderer.drawString(I18n.format("gregtech.recipe.explosive",
- ((ItemStack) value).getDisplayName()), x, y, color);
+ castValue(value).getDisplayName()), x, y, color);
}
@Override
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/PrimitiveProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/PrimitiveProperty.java
similarity index 55%
rename from src/main/java/gregtech/api/recipes/recipeproperties/PrimitiveProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/PrimitiveProperty.java
index 908127d3573..22b49f00bb8 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/PrimitiveProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/PrimitiveProperty.java
@@ -1,13 +1,20 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagByte;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import org.jetbrains.annotations.NotNull;
+
/**
* Simple Marker Property to tell JEI to not display Total EU and EU/t.
*/
-public class PrimitiveProperty extends RecipeProperty {
+public final class PrimitiveProperty extends RecipeProperty {
public static final String KEY = "primitive_property";
private static PrimitiveProperty INSTANCE;
@@ -19,16 +26,27 @@ private PrimitiveProperty() {
public static PrimitiveProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new PrimitiveProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagByte((byte) (castValue(value) ? 1 : 0));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagByte) nbt).getByte() == 1;
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {}
@Override
- public int getInfoHeight(Object value) {
+ public int getInfoHeight(@NotNull Object value) {
return 0;
}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/ResearchProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/ResearchProperty.java
similarity index 50%
rename from src/main/java/gregtech/api/recipes/recipeproperties/ResearchProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/ResearchProperty.java
index ec4d6ab105e..15b538fa5d6 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/ResearchProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/ResearchProperty.java
@@ -1,7 +1,12 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@@ -21,10 +26,31 @@ private ResearchProperty() {
public static ResearchProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new ResearchProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ NBTTagList list = new NBTTagList();
+ for (var entry : castValue(value)) {
+ list.appendTag(entry.serializeNBT());
+ }
+ return list;
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ NBTTagList list = (NBTTagList) nbt;
+ ResearchPropertyData data = new ResearchPropertyData();
+ for (int i = 0; i < list.tagCount(); i++) {
+ data.add(ResearchPropertyData.ResearchEntry.deserializeFromNBT(list.getCompoundTagAt(i)));
+ }
+
+ return data;
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(@NotNull Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/ResearchPropertyData.java b/src/main/java/gregtech/api/recipes/properties/impl/ResearchPropertyData.java
similarity index 66%
rename from src/main/java/gregtech/api/recipes/recipeproperties/ResearchPropertyData.java
rename to src/main/java/gregtech/api/recipes/properties/impl/ResearchPropertyData.java
index 4b199221d6c..95a5159aac0 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/ResearchPropertyData.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/ResearchPropertyData.java
@@ -1,6 +1,7 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
import org.jetbrains.annotations.NotNull;
@@ -12,8 +13,6 @@ public final class ResearchPropertyData implements Iterable entries = new ArrayList<>();
- public ResearchPropertyData() {}
-
/**
* @param entry the entry to add
*/
@@ -46,14 +45,23 @@ public ResearchEntry(@NotNull String researchId, @NotNull ItemStack dataItem) {
this.dataItem = dataItem;
}
- @NotNull
- public String getResearchId() {
+ public @NotNull String researchId() {
return researchId;
}
- @NotNull
- public ItemStack getDataItem() {
+ public @NotNull ItemStack dataItem() {
return dataItem;
}
+
+ public @NotNull NBTTagCompound serializeNBT() {
+ NBTTagCompound tag = new NBTTagCompound();
+ tag.setString("researchId", researchId);
+ tag.setTag("dataItem", dataItem.serializeNBT());
+ return tag;
+ }
+
+ public static @NotNull ResearchEntry deserializeFromNBT(@NotNull NBTTagCompound tag) {
+ return new ResearchEntry(tag.getString("researchId"), new ItemStack(tag.getCompoundTag("dataItem")));
+ }
}
}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/ScanProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/ScanProperty.java
similarity index 56%
rename from src/main/java/gregtech/api/recipes/recipeproperties/ScanProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/ScanProperty.java
index 8018561a710..4e80ca61c20 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/ScanProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/ScanProperty.java
@@ -1,13 +1,18 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagByte;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.jetbrains.annotations.NotNull;
-public class ScanProperty extends RecipeProperty {
+public final class ScanProperty extends RecipeProperty {
public static final String KEY = "scan";
@@ -21,10 +26,21 @@ private ScanProperty() {
public static ScanProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new ScanProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagByte((byte) (castValue(value) ? 1 : 0));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagByte) nbt).getByte() == 1;
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/TemperatureProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/TemperatureProperty.java
similarity index 79%
rename from src/main/java/gregtech/api/recipes/recipeproperties/TemperatureProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/TemperatureProperty.java
index c9c1681d9ae..3764158baed 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/TemperatureProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/TemperatureProperty.java
@@ -1,9 +1,13 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import gregtech.api.unification.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagInt;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@@ -13,7 +17,7 @@
import java.util.Map;
import java.util.TreeMap;
-public class TemperatureProperty extends RecipeProperty {
+public final class TemperatureProperty extends RecipeProperty {
public static final String KEY = "temperature";
@@ -28,10 +32,21 @@ private TemperatureProperty() {
public static TemperatureProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new TemperatureProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagInt(castValue(value));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagInt) nbt).getInt();
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/TotalComputationProperty.java b/src/main/java/gregtech/api/recipes/properties/impl/TotalComputationProperty.java
similarity index 56%
rename from src/main/java/gregtech/api/recipes/recipeproperties/TotalComputationProperty.java
rename to src/main/java/gregtech/api/recipes/properties/impl/TotalComputationProperty.java
index a6247be32c4..0704e44cb46 100644
--- a/src/main/java/gregtech/api/recipes/recipeproperties/TotalComputationProperty.java
+++ b/src/main/java/gregtech/api/recipes/properties/impl/TotalComputationProperty.java
@@ -1,27 +1,45 @@
-package gregtech.api.recipes.recipeproperties;
+package gregtech.api.recipes.properties.impl;
+
+import gregtech.api.GregTechAPI;
+import gregtech.api.recipes.properties.RecipeProperty;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagInt;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
-public class TotalComputationProperty extends RecipeProperty {
+import org.jetbrains.annotations.NotNull;
+
+public final class TotalComputationProperty extends RecipeProperty {
public static final String KEY = "total_computation";
private static TotalComputationProperty INSTANCE;
- protected TotalComputationProperty() {
+ private TotalComputationProperty() {
super(KEY, Integer.class);
}
public static TotalComputationProperty getInstance() {
if (INSTANCE == null) {
INSTANCE = new TotalComputationProperty();
+ GregTechAPI.RECIPE_PROPERTIES.register(KEY, INSTANCE);
}
return INSTANCE;
}
+ @Override
+ public @NotNull NBTBase serialize(@NotNull Object value) {
+ return new NBTTagInt(castValue(value));
+ }
+
+ @Override
+ public @NotNull Object deserialize(@NotNull NBTBase nbt) {
+ return ((NBTTagInt) nbt).getInt();
+ }
+
@Override
@SideOnly(Side.CLIENT)
public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/DefaultProperty.java b/src/main/java/gregtech/api/recipes/recipeproperties/DefaultProperty.java
deleted file mode 100644
index 1579297b2cd..00000000000
--- a/src/main/java/gregtech/api/recipes/recipeproperties/DefaultProperty.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package gregtech.api.recipes.recipeproperties;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.resources.I18n;
-import net.minecraftforge.fml.relauncher.Side;
-import net.minecraftforge.fml.relauncher.SideOnly;
-
-public class DefaultProperty extends RecipeProperty {
-
- public DefaultProperty(String key, Class type) {
- super(key, type);
- }
-
- @SideOnly(Side.CLIENT)
- public void drawInfo(Minecraft minecraft, int x, int y, int color, Object value) {
- minecraft.fontRenderer.drawString(I18n.format("gregtech.recipe." + getKey(),
- castValue(value)), x, y, color);
- }
-}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/EmptyRecipePropertyStorage.java b/src/main/java/gregtech/api/recipes/recipeproperties/EmptyRecipePropertyStorage.java
deleted file mode 100644
index 89f6bb201d6..00000000000
--- a/src/main/java/gregtech/api/recipes/recipeproperties/EmptyRecipePropertyStorage.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package gregtech.api.recipes.recipeproperties;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-public final class EmptyRecipePropertyStorage implements IRecipePropertyStorage {
-
- public static final EmptyRecipePropertyStorage INSTANCE = new EmptyRecipePropertyStorage();
-
- private EmptyRecipePropertyStorage() {}
-
- @Override
- public boolean store(RecipeProperty> recipeProperty, Object value) {
- return false;
- }
-
- @Override
- public boolean remove(RecipeProperty> recipeProperty) {
- return false;
- }
-
- @Override
- public void freeze(boolean frozen) {}
-
- @Override
- public IRecipePropertyStorage copy() {
- return null; // Fresh for RecipeBuilder to handle
- }
-
- @Override
- public int getSize() {
- return 0;
- }
-
- @Override
- public Set, Object>> getRecipeProperties() {
- return Collections.emptySet();
- }
-
- @Override
- public T getRecipePropertyValue(RecipeProperty recipeProperty, T defaultValue) {
- return defaultValue;
- }
-
- @Override
- public boolean hasRecipeProperty(RecipeProperty> recipeProperty) {
- return false;
- }
-
- @Override
- public Set getRecipePropertyKeys() {
- return Collections.emptySet();
- }
-
- @Override
- public Set> getPropertyTypes() {
- return Collections.emptySet();
- }
-
- @Override
- public Object getRawRecipePropertyValue(String key) {
- return null;
- }
-}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/IRecipePropertyStorage.java b/src/main/java/gregtech/api/recipes/recipeproperties/IRecipePropertyStorage.java
deleted file mode 100644
index 9781e2484ce..00000000000
--- a/src/main/java/gregtech/api/recipes/recipeproperties/IRecipePropertyStorage.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package gregtech.api.recipes.recipeproperties;
-
-import java.util.Map;
-import java.util.Set;
-
-public interface IRecipePropertyStorage {
-
- /**
- * Stores new {@link RecipeProperty} with value
- *
- * @param recipeProperty {@link RecipeProperty}
- * @param value value
- * @return {@code true} if store succeeds; otherwise {@code false}
- */
- boolean store(RecipeProperty> recipeProperty, Object value);
-
- boolean remove(RecipeProperty> recipeProperty);
-
- void freeze(boolean frozen);
-
- IRecipePropertyStorage copy();
-
- /**
- * Provides information how many {@link RecipeProperty} are stored
- *
- * @return number of stored {@link RecipeProperty}
- */
- int getSize();
-
- /**
- * Provides all stored {@link RecipeProperty}
- *
- * @return all stored {@link RecipeProperty} and values
- */
- Set, Object>> getRecipeProperties();
-
- /**
- * Provides casted value for one specific {@link RecipeProperty} if is stored or defaultValue
- *
- * @param recipeProperty {@link RecipeProperty}
- * @param defaultValue Default value if recipeProperty is not found
- * @param Type of returned value
- * @return value tied with provided recipeProperty on success; otherwise defaultValue
- */
- T getRecipePropertyValue(RecipeProperty recipeProperty, T defaultValue);
-
- boolean hasRecipeProperty(RecipeProperty> recipeProperty);
-
- Set getRecipePropertyKeys();
-
- Set> getPropertyTypes();
-
- /**
- * Provides un-casted value for one specific {@link RecipeProperty} searched by key
- *
- * @param key Key of stored {@link RecipeProperty}
- * @return {@link Object} value on success; otherwise {@code null}
- */
- Object getRawRecipePropertyValue(String key);
-}
diff --git a/src/main/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorage.java b/src/main/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorage.java
deleted file mode 100644
index cf38c40ef3e..00000000000
--- a/src/main/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorage.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package gregtech.api.recipes.recipeproperties;
-
-import gregtech.api.util.GTLog;
-
-import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class RecipePropertyStorage implements IRecipePropertyStorage {
-
- private final Map, Object> recipeProperties;
-
- private boolean frozen = false;
-
- public RecipePropertyStorage() {
- recipeProperties = new Object2ObjectArrayMap<>(1);
- }
-
- private RecipePropertyStorage(Map, Object> recipeProperties) {
- this();
- this.recipeProperties.putAll(recipeProperties);
- }
-
- @Override
- public boolean store(RecipeProperty> recipeProperty, Object value) {
- boolean success = true;
- String key = recipeProperty.getKey();
- if (frozen) {
- GTLog.logger.warn("Unable to add RecipeProperty with key {} as the storage is frozen", key);
- success = false;
- }
- for (RecipeProperty> existingRecipeProperty : recipeProperties.keySet()) {
- if (existingRecipeProperty.getKey().equals(key)) {
- GTLog.logger.warn("Unable to add RecipeProperty with key {} as it already exists", key);
- success = false;
- }
- }
-
- if (value == null) {
- GTLog.logger.warn("Provided value is null for RecipeProperty with key {}", key);
- success = false;
- }
-
- try {
- recipeProperty.castValue(value);
- } catch (ClassCastException e) {
- GTLog.logger.warn("Provided incorrect value for RecipeProperty with key {}", key, e);
- success = false;
- }
-
- if (success) {
- recipeProperties.put(recipeProperty, value);
- } else {
- GTLog.logger.warn("RecipePropertyStorage error found", new Throwable());
- }
-
- return success;
- }
-
- @Override
- public boolean remove(RecipeProperty> recipeProperty) {
- return this.recipeProperties.remove(recipeProperty) != null;
- }
-
- @Override
- public void freeze(boolean frozen) {
- this.frozen = frozen;
- }
-
- @Override
- public IRecipePropertyStorage copy() {
- return new RecipePropertyStorage(this.recipeProperties);
- }
-
- @Override
- public int getSize() {
- return recipeProperties.size();
- }
-
- @Override
- public Set, Object>> getRecipeProperties() {
- return this.recipeProperties.entrySet();
- }
-
- @Override
- public T getRecipePropertyValue(RecipeProperty recipeProperty, T defaultValue) {
- Object value = recipeProperties.get(recipeProperty);
-
- if (value == null) {
- return defaultValue;
- }
-
- return recipeProperty.castValue(value);
- }
-
- public boolean hasRecipeProperty(RecipeProperty> recipeProperty) {
- return recipeProperties.containsKey(recipeProperty);
- }
-
- @Override
- public Set getRecipePropertyKeys() {
- HashSet keys = new HashSet<>();
-
- recipeProperties.keySet().forEach(recipeProperty -> keys.add(recipeProperty.getKey()));
-
- return keys;
- }
-
- @Override
- public Set> getPropertyTypes() {
- return recipeProperties.keySet();
- }
-
- @Override
- public Object getRawRecipePropertyValue(String key) {
- RecipeProperty> recipeProperty = getRecipePropertyValue(key);
- if (recipeProperty != null) {
- return recipeProperties.get(recipeProperty);
- }
-
- return null;
- }
-
- private RecipeProperty> getRecipePropertyValue(String key) {
- for (RecipeProperty> recipeProperty : recipeProperties.keySet()) {
- if (recipeProperty.getKey().equals(key))
- return recipeProperty;
- }
-
- return null;
- }
-}
diff --git a/src/main/java/gregtech/api/recipes/ui/RecipeMapUI.java b/src/main/java/gregtech/api/recipes/ui/RecipeMapUI.java
index a85fd546cae..a6d66d3e62e 100644
--- a/src/main/java/gregtech/api/recipes/ui/RecipeMapUI.java
+++ b/src/main/java/gregtech/api/recipes/ui/RecipeMapUI.java
@@ -283,8 +283,10 @@ public int getPropertyHeightShift() {
int maxPropertyCount = 0;
if (shouldShiftWidgets()) {
for (Recipe recipe : recipeMap.getRecipeList()) {
- if (recipe.getPropertyCount() > maxPropertyCount)
- maxPropertyCount = recipe.getPropertyCount();
+ int count = recipe.propertyStorage().size();
+ if (count > maxPropertyCount) {
+ maxPropertyCount = count;
+ }
}
}
return maxPropertyCount * 10; // GTRecipeWrapper#LINE_HEIGHT
diff --git a/src/main/java/gregtech/api/util/AssemblyLineManager.java b/src/main/java/gregtech/api/util/AssemblyLineManager.java
index a2652acfa84..7601c0e73cd 100644
--- a/src/main/java/gregtech/api/util/AssemblyLineManager.java
+++ b/src/main/java/gregtech/api/util/AssemblyLineManager.java
@@ -11,7 +11,7 @@
import gregtech.api.recipes.ingredients.nbtmatch.NBTMatcher;
import gregtech.api.recipes.machines.IScannerRecipeMap;
import gregtech.api.recipes.machines.RecipeMapScanner;
-import gregtech.api.recipes.recipeproperties.ScanProperty;
+import gregtech.api.recipes.properties.impl.ScanProperty;
import gregtech.common.ConfigHolder;
import gregtech.common.items.MetaItems;
diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java
index 6817aaa7ce5..1a43a28aa62 100644
--- a/src/main/java/gregtech/common/CommonProxy.java
+++ b/src/main/java/gregtech/common/CommonProxy.java
@@ -10,7 +10,7 @@
import gregtech.api.recipes.GTRecipeInputCache;
import gregtech.api.recipes.ModHandler;
import gregtech.api.recipes.ingredients.GTRecipeOreInput;
-import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty;
+import gregtech.api.recipes.properties.impl.FusionEUToStartProperty;
import gregtech.api.terminal.TerminalRegistry;
import gregtech.api.unification.material.Material;
import gregtech.api.unification.material.info.MaterialFlags;
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityAssemblyLine.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityAssemblyLine.java
index fb2de88df33..69b648b41cb 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityAssemblyLine.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityAssemblyLine.java
@@ -14,7 +14,7 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.recipes.ingredients.GTRecipeInput;
-import gregtech.api.recipes.recipeproperties.ResearchProperty;
+import gregtech.api.recipes.properties.impl.ResearchProperty;
import gregtech.api.util.GTUtility;
import gregtech.api.util.RelativeDirection;
import gregtech.client.particle.GTLaserBeamParticle;
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java
index d71dca8cd0d..b1bd30b8574 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCrackingUnit.java
@@ -12,7 +12,7 @@
import gregtech.api.pattern.PatternMatchContext;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextComponentUtil;
import gregtech.client.renderer.ICubeRenderer;
@@ -150,7 +150,7 @@ public CrackingUnitWorkableHandler(RecipeMapMultiblockController tileEntity) {
}
@Override
- protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPost(ocResult, storage);
int coilTier = ((MetaTileEntityCrackingUnit) metaTileEntity).getCoilTier();
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java
index 78d9449eaf2..89c277d7c8d 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java
@@ -17,7 +17,7 @@
import gregtech.api.pattern.PatternMatchContext;
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeMaps;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextComponentUtil;
import gregtech.api.util.TextFormattingUtil;
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFusionReactor.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFusionReactor.java
index 4b6b9db00d5..b9a918639f3 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFusionReactor.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFusionReactor.java
@@ -30,8 +30,8 @@
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.recipes.logic.OCParams;
-import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
+import gregtech.api.recipes.properties.impl.FusionEUToStartProperty;
import gregtech.api.util.RelativeDirection;
import gregtech.api.util.TextComponentUtil;
import gregtech.api.util.TextFormattingUtil;
@@ -637,13 +637,13 @@ public boolean checkRecipe(@NotNull Recipe recipe) {
}
@Override
- protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPre(@NotNull OCParams ocParams, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPre(ocParams, storage);
// Limit the number of OCs to the difference in fusion reactor MK.
// I.e., a MK2 reactor can overclock a MK1 recipe once, and a
// MK3 reactor can overclock a MK2 recipe once, or a MK1 recipe twice.
- long euToStart = storage.getRecipePropertyValue(FusionEUToStartProperty.getInstance(), 0L);
+ long euToStart = storage.get(FusionEUToStartProperty.getInstance(), 0L);
int fusionTier = FusionEUToStartProperty.getFusionTier(euToStart);
if (fusionTier != 0) fusionTier = MetaTileEntityFusionReactor.this.tier - fusionTier;
ocParams.setOcAmount(Math.min(fusionTier, ocParams.ocAmount()));
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java
index d25c923630d..71fca7ba8d4 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityMultiSmelter.java
@@ -17,7 +17,7 @@
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
import gregtech.api.recipes.machines.RecipeMapFurnace;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextComponentUtil;
import gregtech.api.util.TextFormattingUtil;
@@ -208,7 +208,7 @@ public ParallelLogicType getParallelLogicType() {
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
standardOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(),
getOverclockingVoltageFactor());
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java
index 7a8fd7a9162..4759bb1dec7 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityProcessingArray.java
@@ -24,7 +24,7 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextComponentUtil;
import gregtech.api.util.TextFormattingUtil;
@@ -417,7 +417,7 @@ protected int getNumberOfOCs(long recipeEUt) {
@Override
protected void runOverclockingLogic(@NotNull OCParams ocParams, @NotNull OCResult ocResult,
- @NotNull IRecipePropertyStorage propertyStorage, long maxVoltage) {
+ @NotNull RecipePropertyStorage propertyStorage, long maxVoltage) {
subTickNonParallelOC(ocParams, ocResult, maxVoltage, getOverclockingDurationFactor(),
getOverclockingVoltageFactor());
}
diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java
index efda75b7dc6..b4715563582 100644
--- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java
+++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityPyrolyseOven.java
@@ -12,7 +12,7 @@
import gregtech.api.pattern.PatternMatchContext;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.recipes.logic.OCResult;
-import gregtech.api.recipes.recipeproperties.IRecipePropertyStorage;
+import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.util.GTUtility;
import gregtech.api.util.TextComponentUtil;
import gregtech.client.renderer.ICubeRenderer;
@@ -173,7 +173,7 @@ public PyrolyseOvenWorkableHandler(RecipeMapMultiblockController tileEntity) {
}
@Override
- protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull IRecipePropertyStorage storage) {
+ protected void modifyOverclockPost(@NotNull OCResult ocResult, @NotNull RecipePropertyStorage storage) {
super.modifyOverclockPost(ocResult, storage);
int coilTier = ((MetaTileEntityPyrolyseOven) metaTileEntity).getCoilTier();
diff --git a/src/main/java/gregtech/core/CoreModule.java b/src/main/java/gregtech/core/CoreModule.java
index 149c19344ec..aecbe907d48 100644
--- a/src/main/java/gregtech/core/CoreModule.java
+++ b/src/main/java/gregtech/core/CoreModule.java
@@ -20,7 +20,7 @@
import gregtech.api.mui.GTGuis;
import gregtech.api.recipes.ModHandler;
import gregtech.api.recipes.RecipeMap;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.Materials;
import gregtech.api.unification.material.event.MaterialEvent;
diff --git a/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipe.java b/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipe.java
index 728c190a0d3..ac71e2f0fbb 100644
--- a/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipe.java
+++ b/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipe.java
@@ -15,7 +15,6 @@
import stanhebben.zenscript.annotations.ZenGetter;
import stanhebben.zenscript.annotations.ZenMethod;
-import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -90,16 +89,6 @@ public boolean isHidden() {
return this.backingRecipe.isHidden();
}
- @ZenGetter("propertyKeys")
- public List getPropertyKeys() {
- return new ArrayList<>(this.backingRecipe.getPropertyKeys());
- }
-
- @ZenMethod
- public Object getProperty(String key) {
- return this.backingRecipe.getPropertyRaw(key);
- }
-
@ZenMethod
public boolean remove() {
return this.recipeMap.removeRecipe(this.backingRecipe);
diff --git a/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipeBuilder.java b/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipeBuilder.java
index be74a57456c..b419cc4960b 100644
--- a/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipeBuilder.java
+++ b/src/main/java/gregtech/integration/crafttweaker/recipe/CTRecipeBuilder.java
@@ -220,7 +220,7 @@ public CTRecipeBuilder fluidOutputs(ILiquidStack... ingredients) {
@ZenMethod
public CTRecipeBuilder property(String key, int value) {
- boolean applied = this.backingBuilder.applyProperty(key, value);
+ boolean applied = this.backingBuilder.applyPropertyCT(key, value);
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
@@ -231,7 +231,7 @@ public CTRecipeBuilder property(String key, int value) {
@ZenMethod
public CTRecipeBuilder property(String key, String value) {
- boolean applied = this.backingBuilder.applyProperty(key, value);
+ boolean applied = this.backingBuilder.applyPropertyCT(key, value);
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
@@ -242,7 +242,7 @@ public CTRecipeBuilder property(String key, String value) {
@ZenMethod
public CTRecipeBuilder property(String key, boolean value) {
- boolean applied = this.backingBuilder.applyProperty(key, value);
+ boolean applied = this.backingBuilder.applyPropertyCT(key, value);
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
@@ -253,7 +253,7 @@ public CTRecipeBuilder property(String key, boolean value) {
@ZenMethod
public CTRecipeBuilder property(String key, long value) {
- boolean applied = this.backingBuilder.applyProperty(key, value);
+ boolean applied = this.backingBuilder.applyPropertyCT(key, value);
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
@@ -264,7 +264,7 @@ public CTRecipeBuilder property(String key, long value) {
@ZenMethod
public CTRecipeBuilder property(String key, float value) {
- boolean applied = this.backingBuilder.applyProperty(key, value);
+ boolean applied = this.backingBuilder.applyPropertyCT(key, value);
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
@@ -275,7 +275,7 @@ public CTRecipeBuilder property(String key, float value) {
@ZenMethod
public CTRecipeBuilder property(String key, IItemStack item) {
- boolean applied = this.backingBuilder.applyProperty(key, CraftTweakerMC.getItemStack(item));
+ boolean applied = this.backingBuilder.applyPropertyCT(key, CraftTweakerMC.getItemStack(item));
if (!applied) {
throw new IllegalArgumentException("Property " +
key + " cannot be applied to recipe type " +
diff --git a/src/main/java/gregtech/integration/groovy/GroovyExpansions.java b/src/main/java/gregtech/integration/groovy/GroovyExpansions.java
index ff00a9d1b5b..00a7906fb0e 100644
--- a/src/main/java/gregtech/integration/groovy/GroovyExpansions.java
+++ b/src/main/java/gregtech/integration/groovy/GroovyExpansions.java
@@ -18,7 +18,7 @@ public class GroovyExpansions {
public static > RecipeBuilder property(RecipeBuilder builder, String key,
Object value) {
- if (!builder.applyProperty(key, value)) {
+ if (!builder.applyPropertyCT(key, value)) {
GroovyLog.get().error("Failed to add property '{}' with '{}' to recipe", key, value);
}
return builder;
diff --git a/src/main/java/gregtech/integration/jei/basic/MaterialTreeCategory.java b/src/main/java/gregtech/integration/jei/basic/MaterialTreeCategory.java
index 16a26032f73..b3c8b6e10b2 100644
--- a/src/main/java/gregtech/integration/jei/basic/MaterialTreeCategory.java
+++ b/src/main/java/gregtech/integration/jei/basic/MaterialTreeCategory.java
@@ -2,7 +2,7 @@
import gregtech.api.GTValues;
import gregtech.api.gui.GuiTextures;
-import gregtech.api.recipes.recipeproperties.TemperatureProperty;
+import gregtech.api.recipes.properties.impl.TemperatureProperty;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.Materials;
import gregtech.api.unification.ore.OrePrefix;
diff --git a/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java b/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java
index f0fb97c1f1c..7dae031a66a 100644
--- a/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java
+++ b/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java
@@ -16,10 +16,10 @@
import gregtech.api.recipes.ingredients.GTRecipeInput;
import gregtech.api.recipes.machines.IResearchRecipeMap;
import gregtech.api.recipes.machines.IScannerRecipeMap;
-import gregtech.api.recipes.recipeproperties.ComputationProperty;
-import gregtech.api.recipes.recipeproperties.RecipeProperty;
-import gregtech.api.recipes.recipeproperties.ScanProperty;
-import gregtech.api.recipes.recipeproperties.TotalComputationProperty;
+import gregtech.api.recipes.properties.RecipeProperty;
+import gregtech.api.recipes.properties.impl.ComputationProperty;
+import gregtech.api.recipes.properties.impl.ScanProperty;
+import gregtech.api.recipes.properties.impl.TotalComputationProperty;
import gregtech.api.util.AssemblyLineManager;
import gregtech.api.util.ClipboardUtil;
import gregtech.api.util.GTUtility;
@@ -44,7 +44,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
@@ -239,7 +238,8 @@ public void addIngredientTooltips(@NotNull Collection tooltip, boolean n
@Override
public void drawInfo(@NotNull Minecraft minecraft, int recipeWidth, int recipeHeight, int mouseX, int mouseY) {
super.drawInfo(minecraft, recipeWidth, recipeHeight, mouseX, mouseY);
- var properties = recipe.getPropertyTypes();
+ var storage = recipe.propertyStorage();
+ var properties = storage.values();
boolean drawTotalEU = properties.isEmpty() || properties.stream().noneMatch(RecipeProperty::hideTotalEU);
boolean drawEUt = properties.isEmpty() || properties.stream().noneMatch(RecipeProperty::hideEUt);
boolean drawDuration = properties.isEmpty() || properties.stream().noneMatch(RecipeProperty::hideDuration);
@@ -249,15 +249,18 @@ public void drawInfo(@NotNull Minecraft minecraft, int recipeWidth, int recipeHe
if (drawEUt) defaultLines++;
if (drawDuration) defaultLines++;
- int yPosition = recipeHeight - ((recipe.getUnhiddenPropertyCount() + defaultLines) * 10 - 3);
+ int unhiddenCount = (int) storage.entrySet().stream()
+ .filter((property) -> !property.getKey().isHidden())
+ .count();
+ int yPosition = recipeHeight - ((unhiddenCount + defaultLines) * 10 - 3);
// Default entries
if (drawTotalEU) {
long eu = recipe.getEUt() * recipe.getDuration();
// sadly we still need a custom override here, since computation uses duration and EU/t very differently
- if (recipe.hasProperty(TotalComputationProperty.getInstance()) &&
- recipe.hasProperty(ComputationProperty.getInstance())) {
- int minimumCWUt = recipe.getProperty(ComputationProperty.getInstance(), 1);
+ if (storage.contains(TotalComputationProperty.getInstance()) &&
+ storage.contains(ComputationProperty.getInstance())) {
+ int minimumCWUt = storage.get(ComputationProperty.getInstance(), 1);
minecraft.fontRenderer.drawString(I18n.format("gregtech.recipe.max_eu", eu / minimumCWUt), 0, yPosition,
0x111111);
} else {
@@ -280,10 +283,10 @@ public void drawInfo(@NotNull Minecraft minecraft, int recipeWidth, int recipeHe
}
// Property custom entries
- for (Map.Entry, Object> propertyEntry : recipe.getPropertyValues()) {
+ for (var propertyEntry : storage.entrySet()) {
if (!propertyEntry.getKey().isHidden()) {
RecipeProperty> property = propertyEntry.getKey();
- Object value = propertyEntry.getValue();
+ var value = propertyEntry.getValue();
property.drawInfo(minecraft, 0, yPosition += property.getInfoHeight(value), 0x111111, value, mouseX,
mouseY);
}
@@ -294,7 +297,7 @@ public void drawInfo(@NotNull Minecraft minecraft, int recipeWidth, int recipeHe
@Override
public List getTooltipStrings(int mouseX, int mouseY) {
List tooltips = new ArrayList<>();
- for (var entry : recipe.getPropertyValues()) {
+ for (var entry : recipe.propertyStorage().entrySet()) {
if (!entry.getKey().isHidden()) {
RecipeProperty> property = entry.getKey();
Object value = entry.getValue();
diff --git a/src/main/java/gregtech/integration/jei/recipe/RecipeMapCategory.java b/src/main/java/gregtech/integration/jei/recipe/RecipeMapCategory.java
index 52039a21b07..31dde8f7874 100644
--- a/src/main/java/gregtech/integration/jei/recipe/RecipeMapCategory.java
+++ b/src/main/java/gregtech/integration/jei/recipe/RecipeMapCategory.java
@@ -12,8 +12,8 @@
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.RecipeMaps;
import gregtech.api.recipes.category.GTRecipeCategory;
-import gregtech.api.recipes.recipeproperties.ResearchProperty;
-import gregtech.api.recipes.recipeproperties.ResearchPropertyData;
+import gregtech.api.recipes.properties.impl.ResearchProperty;
+import gregtech.api.recipes.properties.impl.ResearchPropertyData;
import gregtech.api.util.AssemblyLineManager;
import gregtech.api.util.GTUtility;
import gregtech.api.util.LocalizationUtils;
@@ -213,9 +213,9 @@ public void setRecipe(IRecipeLayout recipeLayout, @NotNull GTRecipeWrapper recip
if (data != null) {
List dataItems = new ArrayList<>();
for (ResearchPropertyData.ResearchEntry entry : data) {
- ItemStack dataStick = entry.getDataItem().copy();
+ ItemStack dataStick = entry.dataItem().copy();
AssemblyLineManager.writeResearchToNBT(GTUtility.getOrCreateNbtCompound(dataStick),
- entry.getResearchId());
+ entry.researchId());
dataItems.add(dataStick);
}
itemStackGroup.set(16, dataItems);
diff --git a/src/main/java/gregtech/loaders/recipe/handlers/MaterialRecipeHandler.java b/src/main/java/gregtech/loaders/recipe/handlers/MaterialRecipeHandler.java
index cbdf94add16..3b048b093c6 100644
--- a/src/main/java/gregtech/loaders/recipe/handlers/MaterialRecipeHandler.java
+++ b/src/main/java/gregtech/loaders/recipe/handlers/MaterialRecipeHandler.java
@@ -91,28 +91,28 @@ public static void processDust(OrePrefix dustPrefix, Material mat, DustProperty
.inputs(GTUtility.copy(4, dustStack))
.outputs(GTUtility.copy(3, gemStack))
.chancedOutput(dust, Materials.DarkAsh, 2500, 0)
- .explosivesType(new ItemStack(MetaBlocks.POWDERBARREL, 8))
+ .explosives(new ItemStack(MetaBlocks.POWDERBARREL, 8))
.buildAndRegister();
RecipeMaps.IMPLOSION_RECIPES.recipeBuilder()
.inputs(GTUtility.copy(4, dustStack))
.outputs(GTUtility.copy(3, gemStack))
.chancedOutput(dust, Materials.DarkAsh, 2500, 0)
- .explosivesAmount(4)
+ .explosives(4)
.buildAndRegister();
RecipeMaps.IMPLOSION_RECIPES.recipeBuilder()
.inputs(GTUtility.copy(4, dustStack))
.outputs(GTUtility.copy(3, gemStack))
.chancedOutput(dust, Materials.DarkAsh, 2500, 0)
- .explosivesType(MetaItems.DYNAMITE.getStackForm(2))
+ .explosives(MetaItems.DYNAMITE.getStackForm(2))
.buildAndRegister();
RecipeMaps.IMPLOSION_RECIPES.recipeBuilder()
.inputs(GTUtility.copy(4, dustStack))
.outputs(GTUtility.copy(3, gemStack))
.chancedOutput(dust, Materials.DarkAsh, 2500, 0)
- .explosivesType(new ItemStack(MetaBlocks.ITNT))
+ .explosives(new ItemStack(MetaBlocks.ITNT))
.buildAndRegister();
}
diff --git a/src/test/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorageTest.java b/src/test/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorageTest.java
deleted file mode 100644
index e3daea5e015..00000000000
--- a/src/test/java/gregtech/api/recipes/recipeproperties/RecipePropertyStorageTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package gregtech.api.recipes.recipeproperties;
-
-import org.hamcrest.MatcherAssert;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static org.hamcrest.CoreMatchers.is;
-
-public class RecipePropertyStorageTest {
-
- private static final String propInt1Key = "propInt1";
-
- private static final DefaultProperty propInt1 = new DefaultProperty<>(propInt1Key, Integer.class);
- private static final DefaultProperty propInt2 = new DefaultProperty<>("propInt2", Integer.class);
- private static final DefaultProperty propInt1_2 = new DefaultProperty<>("propInt1", Integer.class);
- private static final DefaultProperty wrongCast = new DefaultProperty<>("wrongCast", Integer.class);
-
- private RecipePropertyStorage storage;
-
- @BeforeEach
- public void initTestStub() {
- this.storage = new RecipePropertyStorage();
- }
-
- @Test
- public void storing_unique_recipe_properties_succeeds() {
- MatcherAssert.assertThat(storage.store(propInt1, 1), is(true));
- MatcherAssert.assertThat(storage.store(propInt2, 1), is(true));
- }
-
- @Test
- public void storing_same_property_twice_fails() {
- MatcherAssert.assertThat(storage.store(propInt1, 1), is(true));
- MatcherAssert.assertThat(storage.store(propInt1, 1), is(false));
- }
-
- @Test
- public void storing_unique_properties_with_same_key_fails() {
- MatcherAssert.assertThat(storage.store(propInt1, 1), is(true));
- MatcherAssert.assertThat(storage.store(propInt1_2, 1), is(false));
- }
-
- @Test
- public void storing_property_with_wrong_cast_fails() {
- MatcherAssert.assertThat(storage.store(wrongCast, "This is not int"), is(false));
- }
-
- @Test
- public void storing_property_without_value_fails() {
- MatcherAssert.assertThat(storage.store(propInt1, null), is(false));
- }
-
- @Test
- public void get_size_returns_correct_value() {
- storage.store(propInt1, 1); // succeeds
-
- MatcherAssert.assertThat(storage.getSize(), is(1));
-
- storage.store(propInt2, 2); // succeeds
-
- MatcherAssert.assertThat(storage.getSize(), is(2));
-
- storage.store(propInt1, 1); // fails
-
- MatcherAssert.assertThat(storage.getSize(), is(2));
- }
-
- @Test
- public void get_recipe_properties_returns_correct_value() {
- storage.store(propInt1, 1); // succeeds
- storage.store(propInt2, 2); // succeeds
-
- Map, Object> map = new HashMap<>();
- map.put(propInt1, 1);
- map.put(propInt2, 2);
- Set, Object>> expectedProperties = map.entrySet();
-
- Set, Object>> actualProperties = storage.getRecipeProperties();
-
- MatcherAssert.assertThat(actualProperties.size(), is(2));
- MatcherAssert.assertThat(
- actualProperties.containsAll(expectedProperties) && expectedProperties.containsAll(actualProperties),
- is(true));
- }
-
- @Test
- public void get_recipe_property_value_returns_correct_value_if_exists() {
- final int expectedValue = 1;
- storage.store(propInt1, expectedValue); // succeeds
-
- int actual = storage.getRecipePropertyValue(propInt1, 0);
-
- MatcherAssert.assertThat(actual, is(expectedValue));
- }
-
- @Test
- public void get_recipe_property_value_returns_default_value_if_does_not_exists() {
- final int expectedValue = 0;
- storage.store(propInt1, 1); // succeeds
-
- int actual = storage.getRecipePropertyValue(propInt2, expectedValue);
-
- MatcherAssert.assertThat(actual, is(expectedValue));
- }
-
- @Test
- // CT way
- public void get_recipe_property_keys() {
- storage.store(propInt1, 1); // succeeds
- storage.store(propInt2, 2); // succeeds
-
- Set expectedKeys = new HashSet<>();
- expectedKeys.add(propInt1.getKey());
- expectedKeys.add(propInt2.getKey());
-
- Set actualKeys = storage.getRecipePropertyKeys();
-
- MatcherAssert.assertThat(expectedKeys.containsAll(actualKeys) && actualKeys.containsAll(expectedKeys),
- is(true));
- }
-
- @Test
- // CT way
- public void get_raw_recipe_property_value_via_string_key() {
- final int expectedValue = 1;
-
- storage.store(propInt1, expectedValue); // succeeds
-
- Object actualValue = storage.getRawRecipePropertyValue(propInt1.getKey());
-
- MatcherAssert.assertThat(actualValue, is(expectedValue));
- }
-}