Skip to content

Commit

Permalink
create new class for display that behaves similar to AdvancedTextWidget
Browse files Browse the repository at this point in the history
  • Loading branch information
ghzdude committed Dec 5, 2024
1 parent aa52a97 commit ec0a767
Show file tree
Hide file tree
Showing 2 changed files with 314 additions and 7 deletions.
293 changes: 293 additions & 0 deletions src/main/java/gregtech/api/mui/widget/GregtechDisplayScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
package gregtech.api.mui.widget;

import gregtech.api.GTValues;
import gregtech.api.metatileentity.multiblock.MultiblockWithDisplayBase;
import gregtech.api.util.GTUtility;
import gregtech.api.util.KeyUtil;
import gregtech.api.util.TextFormattingUtil;

import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.TextFormatting;

import com.cleanroommc.modularui.api.drawable.IKey;
import com.cleanroommc.modularui.api.layout.IViewport;
import com.cleanroommc.modularui.api.layout.IViewportStack;
import com.cleanroommc.modularui.api.widget.IGuiAction;
import com.cleanroommc.modularui.api.widget.Interactable;
import com.cleanroommc.modularui.drawable.Stencil;
import com.cleanroommc.modularui.drawable.TextRenderer;
import com.cleanroommc.modularui.network.NetworkUtils;
import com.cleanroommc.modularui.screen.ModularScreen;
import com.cleanroommc.modularui.screen.viewport.GuiContext;
import com.cleanroommc.modularui.theme.WidgetTheme;
import com.cleanroommc.modularui.utils.HoveredWidgetList;
import com.cleanroommc.modularui.value.sync.SyncHandler;
import com.cleanroommc.modularui.widget.ParentWidget;
import com.cleanroommc.modularui.widget.scroll.ScrollArea;
import com.cleanroommc.modularui.widget.scroll.VerticalScrollData;
import com.cleanroommc.modularui.widget.sizer.Area;
import io.netty.buffer.Unpooled;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.function.Supplier;

public class GregtechDisplayScreen extends ParentWidget<GregtechDisplayScreen> implements IViewport, Interactable {

private final DisplaySyncHandler syncHandler;
private final TextRenderer textRenderer = new TextRenderer();
private final ScrollArea scroll = new ScrollArea();
private final MultiblockWithDisplayBase mte;

public GregtechDisplayScreen(MultiblockWithDisplayBase mte) {
this.mte = mte;
this.syncHandler = new DisplaySyncHandler();
setSyncHandler(this.syncHandler);
scroll.setScrollDataY(new VerticalScrollData());
sizeRel(1f);
listenGuiAction((IGuiAction.MouseReleased) mouseButton -> {
this.scroll.mouseReleased(getContext());
return false;
});
addLine(buffer -> NetworkUtils.writeStringSafe(buffer, mte.getMetaFullName()),
buffer -> KeyUtil.lang(TextFormatting.WHITE, NetworkUtils.readStringSafe(buffer)));
addLine(buffer -> buffer.writeBoolean(mte.isStructureFormed()), buffer -> {
if (buffer.readBoolean()) return null;
return KeyUtil.lang(TextFormatting.RED, "gregtech.multiblock.invalid_structure");
});
}

@Override
public Area getArea() {
return this.scroll;
}

@Override
public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {
if (isInside(stack, x, y)) {
widgets.add(this, stack.peek());
}
}

@Override
public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {}

@Override
public void draw(GuiContext context, WidgetTheme widgetTheme) {
drawKeys();
}

private void drawKeys() {
// draw the keys
int x = getArea().getPadding().left;
int y = getArea().getPadding().top;
for (var key : syncHandler.builtKeys) {
if (key == null) continue;

textRenderer.setPos(x, y - scroll.getScrollY().getScroll());
textRenderer.draw(key.get());
y += 12;
}
}

@Override
public void onResized() {
if (this.scroll.getScrollY() != null) {
this.scroll.getScrollY().clamp(this.scroll);
}
}

@Override
public boolean canHover() {
return super.canHover() ||
this.scroll.isInsideScrollbarArea(getContext().getMouseX(), getContext().getMouseY());
}

@Override
public @NotNull Interactable.Result onMousePressed(int mouseButton) {
GuiContext context = getContext();
if (this.scroll.mouseClicked(context)) {
return Interactable.Result.STOP;
}
return Interactable.Result.IGNORE;
}

@Override
public boolean onMouseScroll(ModularScreen.UpOrDown scrollDirection, int amount) {
return this.scroll.mouseScroll(getContext());
}

@Override
public boolean onMouseRelease(int mouseButton) {
this.scroll.mouseReleased(getContext());
return false;
}

@Override
public void onUpdate() {
super.onUpdate();
this.scroll.drag(getContext().getAbsMouseX(), getContext().getAbsMouseY());
this.scroll.getScrollY().setScrollSize(this.syncHandler.getActiveHeight());
}

public GregtechDisplayScreen addLine(Consumer<PacketBuffer> serializer, Function<PacketBuffer, IKey> deserializer) {
this.syncHandler.addLine(serializer, deserializer);
return getThis();
}

public GregtechDisplayScreen energy(LongSupplier maxVoltage, LongSupplier recipeEUt) {
addLine(buffer -> {
long maxV = maxVoltage.getAsLong();
boolean b = maxV != 0 && maxV >= -recipeEUt.getAsLong();
buffer.writeBoolean(mte.isStructureFormed() && b);
if (b) buffer.writeLong(maxV);
}, buffer -> {
if (!buffer.readBoolean()) return null;
long maxV = buffer.readLong();
// wrap in text component to keep it from being formatted
var voltageName = KeyUtil.string(
GTValues.VOCNF[GTUtility.getFloorTierByVoltage(maxV)]);

return KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.max_energy_per_tick",
TextFormattingUtil.formatNumbers(maxV), voltageName);
});
return getThis();
}

public GregtechDisplayScreen fuelNeeded(Supplier<String> amount, IntSupplier duration) {
addLine(buffer -> {
String s = amount.get();
buffer.writeBoolean(s != null && mte.isStructureFormed());
if (s != null) {
NetworkUtils.writeStringSafe(buffer, s);
buffer.writeInt(duration.getAsInt());
}
}, buffer -> {
if (!buffer.readBoolean()) return null;
return KeyUtil.lang(TextFormatting.GRAY,
"gregtech.multiblock.turbine.fuel_needed",
KeyUtil.string(TextFormatting.RED, NetworkUtils.readStringSafe(buffer)),
KeyUtil.number(TextFormatting.AQUA, buffer.readInt()));
});
return getThis();
}

public GregtechDisplayScreen status() {
addLine(buffer -> {
int i = 0;
var arl = mte.getRecipeLogic();
if (arl != null && !arl.isWorkingEnabled()) {
i = 1;
} else if (arl != null && arl.isActive()) {
i = 2;
}
buffer.writeVarInt(i);
}, buffer -> switch (buffer.readVarInt()) {
case 1 -> KeyUtil.lang(TextFormatting.GOLD, "gregtech.multiblock.work_paused");
case 2 -> KeyUtil.lang(TextFormatting.GREEN, "gregtech.multiblock.running");
default -> KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.idling");
});
return getThis();
}

@Override
public boolean isValidSyncHandler(SyncHandler syncHandler) {
return syncHandler instanceof DisplaySyncHandler;
}

@Override
public void preDraw(GuiContext context, boolean transformed) {
if (!transformed) {
Stencil.applyAtZero(this.scroll, context);
}
}

@Override
public void postDraw(GuiContext context, boolean transformed) {
if (!transformed) {
Stencil.remove();
this.scroll.drawScrollbar();
}
}

private static class DisplaySyncHandler extends SyncHandler {

private final List<Consumer<PacketBuffer>> serializers = new ArrayList<>();
private final List<Function<PacketBuffer, IKey>> deserializers = new ArrayList<>();
private IKey[] builtKeys = new IKey[0];
private final PacketBuffer internalBuffer = new PacketBuffer(Unpooled.buffer());
private boolean dirty = true;
private int activeHeight = 0;

public void addLine(Consumer<PacketBuffer> serializer, Function<PacketBuffer, IKey> deserializer) {
serializers.add(serializer);
deserializers.add(deserializer);
}

private void markDirty() {
this.dirty = true;
}

@Override
public void detectAndSendChanges(boolean init) {
if (init || dirty) {
if (init) buildKeys(null);
if (dirty) dirty = false;
syncToClient(0, this::serializeKeys);
return;
}

IKey[] copy = builtKeys.clone();
internalBuffer.clear();
serializeKeys(internalBuffer);
buildKeys(internalBuffer);

for (int i = 0; i < builtKeys.length; i++) {
if (builtKeys[i] == null && copy[i] == null) continue;
if (builtKeys[i] == null || copy[i] == null || !builtKeys[i].get().equals(copy[i].get())) {
markDirty();
return;
}
}
}

private void buildKeys(PacketBuffer buffer) {
builtKeys = new IKey[deserializers.size()];
activeHeight = 0;
if (buffer == null) return;
Arrays.setAll(builtKeys, i -> {
var key = deserializers.get(i).apply(buffer);
if (key != null) activeHeight += 12;
return key;
});
}

public int getActiveHeight() {
return activeHeight;
}

private void serializeKeys(PacketBuffer buffer) {
serializers.forEach(s -> s.accept(buffer));
}

@Override
public void readOnClient(int id, PacketBuffer buf) throws IOException {
if (id == 0) {
builtKeys = new IKey[deserializers.size()];
for (int i = 0; i < builtKeys.length; i++) {
builtKeys[i] = deserializers.get(i).apply(buf);
}
}
}

@Override
public void readOnServer(int id, PacketBuffer buf) throws IOException {}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gregtech.common.metatileentities.multi.electric.generator;

import gregtech.api.GTValues;
import gregtech.api.capability.GregtechDataCodes;
import gregtech.api.capability.IRotorHolder;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.capability.impl.MultiblockFuelRecipeLogic;
Expand All @@ -12,6 +11,7 @@
import gregtech.api.metatileentity.multiblock.ui.MultiblockUIFactory;
import gregtech.api.mui.GTGuiTextures;
import gregtech.api.mui.sync.FixedIntArraySyncValue;
import gregtech.api.mui.widget.GregtechDisplayScreen;
import gregtech.api.pattern.BlockPattern;
import gregtech.api.pattern.FactoryBlockPattern;
import gregtech.api.pattern.PatternMatchContext;
Expand Down Expand Up @@ -189,15 +189,13 @@ protected void addErrorText(List<ITextComponent> textList) {
@Override
protected MultiblockUIFactory createUIFactory() {
MultiblockFuelRecipeLogic recipeLogic = (MultiblockFuelRecipeLogic) recipeMapWorkable;
boolean noRotor = getRotorHolder() == null;
IntSyncValue efficiency = new IntSyncValue(
() -> 0, null,
() -> getRotorHolder().getRotorEfficiency(), null);
() -> noRotor ? 0 : getRotorHolder().getRotorEfficiency(), null);
IntSyncValue total = new IntSyncValue(
() -> 0, null,
() -> getRotorHolder().getTotalEfficiency(), null);
() -> noRotor ? 0 : getRotorHolder().getTotalEfficiency(), null);
IntSyncValue durability = new IntSyncValue(
() -> 0, null,
() -> getRotorHolder().getRotorDurabilityPercent(), null);
() -> noRotor ? 0 : getRotorHolder().getRotorDurabilityPercent(), null);
BooleanSyncValue rotorFree = new BooleanSyncValue(
this::isRotorFaceFree, null);
StringSyncValue fuelAmount = new StringSyncValue(recipeLogic::getRecipeFluidInputInfo, null);
Expand All @@ -210,6 +208,22 @@ protected MultiblockUIFactory createUIFactory() {
.syncValue("dura", rotorFree)
.syncValue("fuel_amount", fuelAmount)
.syncValue("prev_duration", prevDuration)
.customScreen(() -> new GregtechDisplayScreen(this)
.padding(4)
.energy(this::getMaxVoltage, recipeLogic::getRecipeEUt)
.addLine(buffer -> {
buffer.writeBoolean(isStructureFormed());
if (isStructureFormed())
buffer.writeInt(noRotor ? -1 : getRotorHolder().getTotalEfficiency());
}, buffer -> {
if (!buffer.readBoolean()) return null;
int i = buffer.readInt();
if (i < 0) return null;
return KeyUtil.lang(TextFormatting.GRAY,
"gregtech.multiblock.turbine.efficiency", i);
})
.fuelNeeded(recipeLogic::getRecipeFluidInputInfo, recipeLogic::getPreviousRecipeDuration)
.status())
.configureDisplayText(builder -> builder
.setWorkingStatus(recipeLogic::isWorkingEnabled, recipeLogic::isActive)
.addEnergyProductionLine(getMaxVoltage(), recipeLogic.getRecipeEUt())
Expand Down

0 comments on commit ec0a767

Please sign in to comment.