diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java index b3e29f360..22d09a11a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java @@ -4,13 +4,17 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatteryMachine; +import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.function.Consumer; public abstract class MatteryMenu extends AbstractContainerMenu { protected BlockEntity tile; @@ -18,6 +22,8 @@ public abstract class MatteryMenu extends AbstractContainerMenu { protected Inventory inventory; protected Player ply; + public final ArrayList widget_list = new ArrayList<>(); + protected MatteryMenu(@Nullable MenuType p_38851_, int p_38852_, Inventory inventory) { super(p_38851_, p_38852_); this.inventory = inventory; @@ -29,6 +35,14 @@ public abstract class MatteryMenu extends AbstractContainerMenu { this.tile = tile; } + public void addWidget(AbstractWidget widget, Consumer> consumer) { + if (widget_list.contains(widget)) + return; + + widget_list.add(widget); + consumer.accept(this::addDataSlots); + } + protected void addInventorySlots() { addInventorySlots(97); } @@ -59,6 +73,24 @@ public abstract class MatteryMenu extends AbstractContainerMenu { inventory_slot_index_end = last.index; } + @Override + public void broadcastChanges() { + for (AbstractWidget widget : this.widget_list) { + widget.updateServer(); + } + + super.broadcastChanges(); + } + + @Override + public void broadcastFullState() { + for (AbstractWidget widget : this.widget_list) { + widget.updateServer(); + } + + super.broadcastFullState(); + } + @Override public boolean stillValid(Player player) { if (tile == null) diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/PoweredMatteryMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/PoweredMatteryMenu.java index 8d4d76c0f..e74248a1b 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/PoweredMatteryMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/PoweredMatteryMenu.java @@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage; import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.menu.data.BigDecimalDataContainer; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.widget.BatteryLevelWidget; import javax.annotation.Nullable; @@ -21,6 +22,8 @@ abstract public class PoweredMatteryMenu extends MatteryMenu { public BigDecimalDataContainer energy; public BigDecimalDataContainer max_energy; + public BatteryLevelWidget battery_widget; + protected PoweredMatteryMenu( @Nullable MenuType menuType, int containerID, @@ -30,9 +33,11 @@ abstract public class PoweredMatteryMenu extends MatteryMenu { super(menuType, containerID, inventory, tile); this.tile = tile; - if (tile == null) { + if (tile == null || tile.getCapability(MatteryCapability.ENERGY).resolve().isEmpty()) { energy = new BigDecimalDataContainer(); max_energy = new BigDecimalDataContainer(); + + battery_widget = new BatteryLevelWidget<>(this, 13, 14); } else { energy = new BigDecimalDataContainer() { @Override @@ -53,6 +58,8 @@ abstract public class PoweredMatteryMenu extends MatteryMenu { setDecimal(capability.resolve().get().getMaxBatteryLevel()); } }; + + battery_widget = new BatteryLevelWidget<>(this, 13, 14, tile.getCapability(MatteryCapability.ENERGY).resolve().get()); } this.addDataSlots(energy); diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/data/BigDecimalDataContainer.java b/src/main/java/ru/dbotthepony/mc/otm/menu/data/BigDecimalDataContainer.java index 094bd30b6..8fc03c63a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/data/BigDecimalDataContainer.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/data/BigDecimalDataContainer.java @@ -1,46 +1,54 @@ package ru.dbotthepony.mc.otm.menu.data; import net.minecraft.world.inventory.ContainerData; +import org.apache.commons.lang3.ArrayUtils; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; import java.math.BigDecimal; import java.math.BigInteger; public class BigDecimalDataContainer implements ContainerData { - public static final int NETWORK_PAYLOAD_SIZE = 8; + public static final int NETWORK_PAYLOAD_SIZE = 16; private BigDecimal value; - private final int[] buffer = new int[NETWORK_PAYLOAD_SIZE + 1]; + // working with ints + // networking as shorts + // crazy. + private final int[] buffer = new int[NETWORK_PAYLOAD_SIZE + 2]; public BigDecimal getDecimal() { if (value != null) { return value; } - byte[] _build = new byte[NETWORK_PAYLOAD_SIZE * 4]; + byte[] _build = new byte[NETWORK_PAYLOAD_SIZE * 2]; int build_index = 0; // read payload for (int i = 1; i <= NETWORK_PAYLOAD_SIZE; i++) { - _build[build_index] = (byte) ((buffer[i] & 0xFF000000) >> 24); - _build[build_index + 1] = (byte) ((buffer[i] & 0xFF0000) >> 16); - _build[build_index + 2] = (byte) ((buffer[i] & 0xFF00) >> 8); - _build[build_index + 3] = (byte) (buffer[i] & 0xFF); + _build[build_index] = (byte) ((buffer[i] & 0xFF00) >> 8); + _build[build_index + 1] = (byte) (buffer[i] & 0xFF); - build_index += 4; + build_index += 2; } byte[] build = new byte[_build[0] & 0xFF]; if (_build[0] != 0) { + if (build.length > _build.length - 1) { + OverdriveThatMatters.LOGGER.fatal("Tried to read {} bytes, while buffer allow only up to {} bytes to be read!", build.length, _build.length - 1); + OverdriveThatMatters.LOGGER.fatal("buffer state: {}", ArrayUtils.toString(buffer)); + OverdriveThatMatters.LOGGER.fatal("decoded state: {}", ArrayUtils.toString(_build)); + return value = BigDecimal.ZERO; + } + System.arraycopy(_build, 1, build, 0, build.length); - value = new BigDecimal(new BigInteger(build), buffer[0]); - return value; + return value = new BigDecimal(new BigInteger(build), buffer[0]); } - value = new BigDecimal(0); - return value; + return value = BigDecimal.ZERO; } public void setDecimal(BigDecimal decimal) { @@ -53,9 +61,10 @@ public class BigDecimalDataContainer implements ContainerData { int scale = decimal.scale(); BigInteger integer = decimal.unscaledValue(); - buffer[0] = scale; + buffer[0] = scale & 0xFFFF; + buffer[1] = (scale & 0xFFFF0000) >>> 16; byte[] _build = integer.toByteArray(); - byte[] build = new byte[NETWORK_PAYLOAD_SIZE * 4]; + byte[] build = new byte[NETWORK_PAYLOAD_SIZE * 2]; // insert, shift by one System.arraycopy(_build, 0, build, 1, Math.min(_build.length, NETWORK_PAYLOAD_SIZE * 4 - 1)); @@ -67,12 +76,11 @@ public class BigDecimalDataContainer implements ContainerData { // write for (int i = 1; i <= NETWORK_PAYLOAD_SIZE; i++) { - buffer[i] = (build[build_index] & 0xFF) << 24 | - (build[build_index + 1] & 0xFF) << 16 | - (build[build_index + 2] & 0xFF) << 8 | - (build[build_index + 3] & 0xFF); + buffer[i] = + (build[build_index] & 0xFF) << 8 | + (build[build_index + 1] & 0xFF); - build_index += 4; + build_index += 2; } } @@ -98,6 +106,6 @@ public class BigDecimalDataContainer implements ContainerData { @Override public int getCount() { - return NETWORK_PAYLOAD_SIZE + 1; + return NETWORK_PAYLOAD_SIZE + 2; } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java new file mode 100644 index 000000000..90f3e5904 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/AbstractWidget.java @@ -0,0 +1,56 @@ +package ru.dbotthepony.mc.otm.menu.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.ContainerData; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.menu.MatteryMenu; +import ru.dbotthepony.mc.otm.screen.MatteryScreen; + +import javax.annotation.Nonnull; +import java.util.concurrent.Callable; +import java.util.function.Consumer; + +public abstract class AbstractWidget { + public static final ResourceLocation TEXTURE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets.png"); + + public final T menu; + public int x; + public int y; + protected Consumer register_data; + + protected boolean is_hovered = false; + + public abstract int getImageWidth(); + public abstract int getImageHeight(); + + public abstract int getImageX(); + public abstract int getImageY(); + + public AbstractWidget(@Nonnull T menu, int x, int y) { + this.menu = menu; + this.x = x; + this.y = y; + menu.addWidget(this, (consumer) -> register_data = consumer); + } + + protected void addDataSlots(ContainerData slots) { + register_data.accept(slots); + } + + public void updateIsHovered(int local_x, int local_y, int mouse_x, int mouse_y) { + is_hovered = mouse_x >= x + local_x && mouse_y >= y + local_y && x + local_x + getImageWidth() >= mouse_x && y + local_y + getImageHeight() >= mouse_y; + } + + public boolean isHovered() { + return is_hovered; + } + + abstract public void updateServer(); + + abstract public void renderBackground(MatteryScreen screen, PoseStack pose, int local_x, int local_y, int mouse_x, int mouse_y); + + // true - rendered a tooltip, break the loop + // false - pass + abstract public boolean renderTooltip(MatteryScreen screen, PoseStack pose, int local_x, int local_y, int mouse_x, int mouse_y); +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/widget/BatteryLevelWidget.java b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/BatteryLevelWidget.java new file mode 100644 index 000000000..1db9ba7b4 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/BatteryLevelWidget.java @@ -0,0 +1,94 @@ +package ru.dbotthepony.mc.otm.menu.widget; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.inventory.ContainerData; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; +import ru.dbotthepony.mc.otm.menu.FormattingHelper; +import ru.dbotthepony.mc.otm.menu.MatteryMenu; +import ru.dbotthepony.mc.otm.menu.data.BigDecimalDataContainer; +import ru.dbotthepony.mc.otm.screen.MatteryScreen; + +import java.math.BigDecimal; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class BatteryLevelWidget extends VerticalGaugeWidget { + protected Supplier value_supplier; + protected Supplier max_value_supplier; + + protected final BigDecimalDataContainer value_container = new BigDecimalDataContainer(); + protected final BigDecimalDataContainer max_value_container = new BigDecimalDataContainer(); + + public BatteryLevelWidget(T menu, int x, int y, IMatteryEnergyStorage capability) { + this(menu, x, y, capability::getBatteryLevel, capability::getMaxBatteryLevel); + } + + public BatteryLevelWidget(T menu, int x, int y) { + super(menu, x, y); + addDataSlots(value_container); + addDataSlots(max_value_container); + } + + public BatteryLevelWidget(T menu, int x, int y, Supplier value_supplier, Supplier max_value_supplier) { + this(menu, x, y); + this.value_supplier = value_supplier; + this.max_value_supplier = max_value_supplier; + } + + @Override + public void updateServer() { + if (value_supplier == null || max_value_supplier == null) + return; + + value_container.setDecimal(value_supplier.get()); + max_value_container.setDecimal(max_value_supplier.get()); + } + + @Override + public int getImageWidth() { + return 9; + } + + @Override + public int getImageHeight() { + return 48; + } + + @Override + public int getImageX() { + return 0; + } + + @Override + public int getImageY() { + return 48; + } + + @Override + public boolean renderTooltip(MatteryScreen screen, PoseStack pose, int local_x, int local_y, int mouse_x, int mouse_y) { + if (is_hovered) { + List text = List.of( + new TranslatableComponent("otm.gui.power.percentage_level", String.format("%.2f", getLevel() * 100d)), + FormattingHelper.formatPowerLevel(value_container.getDecimal(), max_value_container.getDecimal()) + ); + + screen.renderComponentTooltip(pose, text, mouse_x, mouse_y); + + return true; + } + + return false; + } + + @Override + float getLevel() { + return max_value_container.getDecimal().compareTo(BigDecimal.ZERO) == 0 ? 0f : value_container.getDecimal().divide(max_value_container.getDecimal(), MatteryCapability.ROUND_RULES).floatValue(); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/widget/VerticalGaugeWidget.java b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/VerticalGaugeWidget.java new file mode 100644 index 000000000..71ca47c40 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/widget/VerticalGaugeWidget.java @@ -0,0 +1,30 @@ +package ru.dbotthepony.mc.otm.menu.widget; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.GameRenderer; +import ru.dbotthepony.mc.otm.menu.MatteryMenu; +import ru.dbotthepony.mc.otm.screen.MatteryScreen; + +abstract public class VerticalGaugeWidget extends AbstractWidget { + public VerticalGaugeWidget(T menu, int x, int y) { + super(menu, x, y); + } + + abstract float getLevel(); + + @Override + public void renderBackground(MatteryScreen screen, PoseStack pose, int local_x, int local_y, int mouse_x, int mouse_y) { + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + RenderSystem.setShaderTexture(0, TEXTURE); + + screen.blit(pose, local_x + x, local_y + y, getImageX(), getImageY(), getImageWidth(), getImageHeight()); + float level = getLevel(); + + if (level > 0.01f) { + int intHeight = (int) Math.floor(level * (float) getImageHeight() + 0.5f); + screen.blit(pose, local_x + x, local_y + y + getImageHeight() - intHeight, getImageX() + getImageWidth(), getImageY() + getImageHeight() - intHeight, getImageWidth(), intHeight); + } + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/BatteryBankScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/BatteryBankScreen.java index 7410d9a99..29bfd755d 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/BatteryBankScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/BatteryBankScreen.java @@ -10,13 +10,6 @@ import ru.dbotthepony.mc.otm.menu.BatteryBankMenu; import ru.dbotthepony.mc.otm.menu.MatteryMenu; public class BatteryBankScreen extends MatteryScreen { - private static final ResourceLocation CONTAINER_BACKGROUND = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/battery_bank.png"); - - @Override - protected ResourceLocation CONTAINER_BACKGROUND() { - return CONTAINER_BACKGROUND; - } - public BatteryBankScreen(BatteryBankMenu p_97741_, Inventory p_97742_, Component p_97743_) { super(p_97741_, p_97742_, p_97743_); power_supplier = () -> menu.energy.getDecimal(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java index b8a2d696e..e023bb377 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; import ru.dbotthepony.mc.otm.menu.slot.MachineInputSlot; import ru.dbotthepony.mc.otm.menu.slot.MachineOutputSlot; +import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget; import java.math.BigDecimal; import java.util.List; @@ -26,9 +27,6 @@ public class MatteryScreen extends AbstractContainerScree protected static final ResourceLocation CONTAINER_BASE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/generic_machine.png"); public static final ResourceLocation WIDGETS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets.png"); - public static final int PROGRESS_WIDGET_WIDTH = 21; - public static final int PROGRESS_WIDGET_HEIGHT = 16; - protected ResourceLocation CONTAINER_BACKGROUND() { return CONTAINER_BASE; } @@ -64,20 +62,26 @@ public class MatteryScreen extends AbstractContainerScree } @Override - protected void renderTooltip(PoseStack p_97791_, int mouseX, int mouseY) { - super.renderTooltip(p_97791_, mouseX, mouseY); + protected void renderTooltip(PoseStack pose, int mouseX, int mouseY) { + super.renderTooltip(pose, mouseX, mouseY); if (this.hoveredSlot == null && menu.getCarried().isEmpty()) { + for (AbstractWidget widget : menu.widget_list) { + if (widget.renderTooltip(this, pose, render_x, render_y, mouseX, mouseY)) { + return; + } + } + if (hovering_power_gauge) { List text = getFormattedPowerLevel(); if (text.size() != 0) - this.renderComponentToolTip(p_97791_, text, mouseX, mouseY, font); + this.renderComponentToolTip(pose, text, mouseX, mouseY, font); } else if (hovering_matter_gauge) { List text = getFormattedMatterLevel(); if (text.size() != 0) - this.renderComponentToolTip(p_97791_, text, mouseX, mouseY, font); + this.renderComponentToolTip(pose, text, mouseX, mouseY, font); } } } @@ -220,6 +224,10 @@ public class MatteryScreen extends AbstractContainerScree render_x = (width - imageWidth) / 2; render_y = (height - imageHeight) / 2; + for (AbstractWidget widget : menu.widget_list) { + widget.updateIsHovered(render_x, render_y, mouseX, mouseY); + } + this.renderBackground(p_98418_); super.render(p_98418_, mouseX, mouseY, p_98421_); this.renderTooltip(p_98418_, mouseX, mouseY); @@ -270,5 +278,9 @@ public class MatteryScreen extends AbstractContainerScree renderRegularSlot(pose, slot1.x, slot1.y); } } + + for (AbstractWidget widget : menu.widget_list) { + widget.renderBackground(this, pose, render_x, render_y, mouseX, mouseY); + } } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/PoweredMachineScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/PoweredMachineScreen.java index 9db00f381..79ae43350 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/PoweredMachineScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/PoweredMachineScreen.java @@ -11,7 +11,7 @@ import java.util.List; public class PoweredMachineScreen extends MatteryScreen { public PoweredMachineScreen(T p_97741_, Inventory p_97742_, Component p_97743_) { super(p_97741_, p_97742_, p_97743_); - power_supplier = () -> menu.energy.getDecimal(); - max_power_supplier = () -> menu.max_energy.getDecimal(); + // power_supplier = () -> menu.energy.getDecimal(); + // max_power_supplier = () -> menu.max_energy.getDecimal(); } }