Skip to content

Commit ec0a767

Browse files
committed
create new class for display that behaves similar to AdvancedTextWidget
1 parent aa52a97 commit ec0a767

File tree

2 files changed

+314
-7
lines changed

2 files changed

+314
-7
lines changed
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package gregtech.api.mui.widget;
2+
3+
import gregtech.api.GTValues;
4+
import gregtech.api.metatileentity.multiblock.MultiblockWithDisplayBase;
5+
import gregtech.api.util.GTUtility;
6+
import gregtech.api.util.KeyUtil;
7+
import gregtech.api.util.TextFormattingUtil;
8+
9+
import net.minecraft.network.PacketBuffer;
10+
import net.minecraft.util.text.TextFormatting;
11+
12+
import com.cleanroommc.modularui.api.drawable.IKey;
13+
import com.cleanroommc.modularui.api.layout.IViewport;
14+
import com.cleanroommc.modularui.api.layout.IViewportStack;
15+
import com.cleanroommc.modularui.api.widget.IGuiAction;
16+
import com.cleanroommc.modularui.api.widget.Interactable;
17+
import com.cleanroommc.modularui.drawable.Stencil;
18+
import com.cleanroommc.modularui.drawable.TextRenderer;
19+
import com.cleanroommc.modularui.network.NetworkUtils;
20+
import com.cleanroommc.modularui.screen.ModularScreen;
21+
import com.cleanroommc.modularui.screen.viewport.GuiContext;
22+
import com.cleanroommc.modularui.theme.WidgetTheme;
23+
import com.cleanroommc.modularui.utils.HoveredWidgetList;
24+
import com.cleanroommc.modularui.value.sync.SyncHandler;
25+
import com.cleanroommc.modularui.widget.ParentWidget;
26+
import com.cleanroommc.modularui.widget.scroll.ScrollArea;
27+
import com.cleanroommc.modularui.widget.scroll.VerticalScrollData;
28+
import com.cleanroommc.modularui.widget.sizer.Area;
29+
import io.netty.buffer.Unpooled;
30+
import org.jetbrains.annotations.NotNull;
31+
32+
import java.io.IOException;
33+
import java.util.ArrayList;
34+
import java.util.Arrays;
35+
import java.util.List;
36+
import java.util.function.Consumer;
37+
import java.util.function.Function;
38+
import java.util.function.IntSupplier;
39+
import java.util.function.LongSupplier;
40+
import java.util.function.Supplier;
41+
42+
public class GregtechDisplayScreen extends ParentWidget<GregtechDisplayScreen> implements IViewport, Interactable {
43+
44+
private final DisplaySyncHandler syncHandler;
45+
private final TextRenderer textRenderer = new TextRenderer();
46+
private final ScrollArea scroll = new ScrollArea();
47+
private final MultiblockWithDisplayBase mte;
48+
49+
public GregtechDisplayScreen(MultiblockWithDisplayBase mte) {
50+
this.mte = mte;
51+
this.syncHandler = new DisplaySyncHandler();
52+
setSyncHandler(this.syncHandler);
53+
scroll.setScrollDataY(new VerticalScrollData());
54+
sizeRel(1f);
55+
listenGuiAction((IGuiAction.MouseReleased) mouseButton -> {
56+
this.scroll.mouseReleased(getContext());
57+
return false;
58+
});
59+
addLine(buffer -> NetworkUtils.writeStringSafe(buffer, mte.getMetaFullName()),
60+
buffer -> KeyUtil.lang(TextFormatting.WHITE, NetworkUtils.readStringSafe(buffer)));
61+
addLine(buffer -> buffer.writeBoolean(mte.isStructureFormed()), buffer -> {
62+
if (buffer.readBoolean()) return null;
63+
return KeyUtil.lang(TextFormatting.RED, "gregtech.multiblock.invalid_structure");
64+
});
65+
}
66+
67+
@Override
68+
public Area getArea() {
69+
return this.scroll;
70+
}
71+
72+
@Override
73+
public void getSelfAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {
74+
if (isInside(stack, x, y)) {
75+
widgets.add(this, stack.peek());
76+
}
77+
}
78+
79+
@Override
80+
public void getWidgetsAt(IViewportStack stack, HoveredWidgetList widgets, int x, int y) {}
81+
82+
@Override
83+
public void draw(GuiContext context, WidgetTheme widgetTheme) {
84+
drawKeys();
85+
}
86+
87+
private void drawKeys() {
88+
// draw the keys
89+
int x = getArea().getPadding().left;
90+
int y = getArea().getPadding().top;
91+
for (var key : syncHandler.builtKeys) {
92+
if (key == null) continue;
93+
94+
textRenderer.setPos(x, y - scroll.getScrollY().getScroll());
95+
textRenderer.draw(key.get());
96+
y += 12;
97+
}
98+
}
99+
100+
@Override
101+
public void onResized() {
102+
if (this.scroll.getScrollY() != null) {
103+
this.scroll.getScrollY().clamp(this.scroll);
104+
}
105+
}
106+
107+
@Override
108+
public boolean canHover() {
109+
return super.canHover() ||
110+
this.scroll.isInsideScrollbarArea(getContext().getMouseX(), getContext().getMouseY());
111+
}
112+
113+
@Override
114+
public @NotNull Interactable.Result onMousePressed(int mouseButton) {
115+
GuiContext context = getContext();
116+
if (this.scroll.mouseClicked(context)) {
117+
return Interactable.Result.STOP;
118+
}
119+
return Interactable.Result.IGNORE;
120+
}
121+
122+
@Override
123+
public boolean onMouseScroll(ModularScreen.UpOrDown scrollDirection, int amount) {
124+
return this.scroll.mouseScroll(getContext());
125+
}
126+
127+
@Override
128+
public boolean onMouseRelease(int mouseButton) {
129+
this.scroll.mouseReleased(getContext());
130+
return false;
131+
}
132+
133+
@Override
134+
public void onUpdate() {
135+
super.onUpdate();
136+
this.scroll.drag(getContext().getAbsMouseX(), getContext().getAbsMouseY());
137+
this.scroll.getScrollY().setScrollSize(this.syncHandler.getActiveHeight());
138+
}
139+
140+
public GregtechDisplayScreen addLine(Consumer<PacketBuffer> serializer, Function<PacketBuffer, IKey> deserializer) {
141+
this.syncHandler.addLine(serializer, deserializer);
142+
return getThis();
143+
}
144+
145+
public GregtechDisplayScreen energy(LongSupplier maxVoltage, LongSupplier recipeEUt) {
146+
addLine(buffer -> {
147+
long maxV = maxVoltage.getAsLong();
148+
boolean b = maxV != 0 && maxV >= -recipeEUt.getAsLong();
149+
buffer.writeBoolean(mte.isStructureFormed() && b);
150+
if (b) buffer.writeLong(maxV);
151+
}, buffer -> {
152+
if (!buffer.readBoolean()) return null;
153+
long maxV = buffer.readLong();
154+
// wrap in text component to keep it from being formatted
155+
var voltageName = KeyUtil.string(
156+
GTValues.VOCNF[GTUtility.getFloorTierByVoltage(maxV)]);
157+
158+
return KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.max_energy_per_tick",
159+
TextFormattingUtil.formatNumbers(maxV), voltageName);
160+
});
161+
return getThis();
162+
}
163+
164+
public GregtechDisplayScreen fuelNeeded(Supplier<String> amount, IntSupplier duration) {
165+
addLine(buffer -> {
166+
String s = amount.get();
167+
buffer.writeBoolean(s != null && mte.isStructureFormed());
168+
if (s != null) {
169+
NetworkUtils.writeStringSafe(buffer, s);
170+
buffer.writeInt(duration.getAsInt());
171+
}
172+
}, buffer -> {
173+
if (!buffer.readBoolean()) return null;
174+
return KeyUtil.lang(TextFormatting.GRAY,
175+
"gregtech.multiblock.turbine.fuel_needed",
176+
KeyUtil.string(TextFormatting.RED, NetworkUtils.readStringSafe(buffer)),
177+
KeyUtil.number(TextFormatting.AQUA, buffer.readInt()));
178+
});
179+
return getThis();
180+
}
181+
182+
public GregtechDisplayScreen status() {
183+
addLine(buffer -> {
184+
int i = 0;
185+
var arl = mte.getRecipeLogic();
186+
if (arl != null && !arl.isWorkingEnabled()) {
187+
i = 1;
188+
} else if (arl != null && arl.isActive()) {
189+
i = 2;
190+
}
191+
buffer.writeVarInt(i);
192+
}, buffer -> switch (buffer.readVarInt()) {
193+
case 1 -> KeyUtil.lang(TextFormatting.GOLD, "gregtech.multiblock.work_paused");
194+
case 2 -> KeyUtil.lang(TextFormatting.GREEN, "gregtech.multiblock.running");
195+
default -> KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.idling");
196+
});
197+
return getThis();
198+
}
199+
200+
@Override
201+
public boolean isValidSyncHandler(SyncHandler syncHandler) {
202+
return syncHandler instanceof DisplaySyncHandler;
203+
}
204+
205+
@Override
206+
public void preDraw(GuiContext context, boolean transformed) {
207+
if (!transformed) {
208+
Stencil.applyAtZero(this.scroll, context);
209+
}
210+
}
211+
212+
@Override
213+
public void postDraw(GuiContext context, boolean transformed) {
214+
if (!transformed) {
215+
Stencil.remove();
216+
this.scroll.drawScrollbar();
217+
}
218+
}
219+
220+
private static class DisplaySyncHandler extends SyncHandler {
221+
222+
private final List<Consumer<PacketBuffer>> serializers = new ArrayList<>();
223+
private final List<Function<PacketBuffer, IKey>> deserializers = new ArrayList<>();
224+
private IKey[] builtKeys = new IKey[0];
225+
private final PacketBuffer internalBuffer = new PacketBuffer(Unpooled.buffer());
226+
private boolean dirty = true;
227+
private int activeHeight = 0;
228+
229+
public void addLine(Consumer<PacketBuffer> serializer, Function<PacketBuffer, IKey> deserializer) {
230+
serializers.add(serializer);
231+
deserializers.add(deserializer);
232+
}
233+
234+
private void markDirty() {
235+
this.dirty = true;
236+
}
237+
238+
@Override
239+
public void detectAndSendChanges(boolean init) {
240+
if (init || dirty) {
241+
if (init) buildKeys(null);
242+
if (dirty) dirty = false;
243+
syncToClient(0, this::serializeKeys);
244+
return;
245+
}
246+
247+
IKey[] copy = builtKeys.clone();
248+
internalBuffer.clear();
249+
serializeKeys(internalBuffer);
250+
buildKeys(internalBuffer);
251+
252+
for (int i = 0; i < builtKeys.length; i++) {
253+
if (builtKeys[i] == null && copy[i] == null) continue;
254+
if (builtKeys[i] == null || copy[i] == null || !builtKeys[i].get().equals(copy[i].get())) {
255+
markDirty();
256+
return;
257+
}
258+
}
259+
}
260+
261+
private void buildKeys(PacketBuffer buffer) {
262+
builtKeys = new IKey[deserializers.size()];
263+
activeHeight = 0;
264+
if (buffer == null) return;
265+
Arrays.setAll(builtKeys, i -> {
266+
var key = deserializers.get(i).apply(buffer);
267+
if (key != null) activeHeight += 12;
268+
return key;
269+
});
270+
}
271+
272+
public int getActiveHeight() {
273+
return activeHeight;
274+
}
275+
276+
private void serializeKeys(PacketBuffer buffer) {
277+
serializers.forEach(s -> s.accept(buffer));
278+
}
279+
280+
@Override
281+
public void readOnClient(int id, PacketBuffer buf) throws IOException {
282+
if (id == 0) {
283+
builtKeys = new IKey[deserializers.size()];
284+
for (int i = 0; i < builtKeys.length; i++) {
285+
builtKeys[i] = deserializers.get(i).apply(buf);
286+
}
287+
}
288+
}
289+
290+
@Override
291+
public void readOnServer(int id, PacketBuffer buf) throws IOException {}
292+
}
293+
}

src/main/java/gregtech/common/metatileentities/multi/electric/generator/MetaTileEntityLargeTurbine.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package gregtech.common.metatileentities.multi.electric.generator;
22

33
import gregtech.api.GTValues;
4-
import gregtech.api.capability.GregtechDataCodes;
54
import gregtech.api.capability.IRotorHolder;
65
import gregtech.api.capability.impl.FluidTankList;
76
import gregtech.api.capability.impl.MultiblockFuelRecipeLogic;
@@ -12,6 +11,7 @@
1211
import gregtech.api.metatileentity.multiblock.ui.MultiblockUIFactory;
1312
import gregtech.api.mui.GTGuiTextures;
1413
import gregtech.api.mui.sync.FixedIntArraySyncValue;
14+
import gregtech.api.mui.widget.GregtechDisplayScreen;
1515
import gregtech.api.pattern.BlockPattern;
1616
import gregtech.api.pattern.FactoryBlockPattern;
1717
import gregtech.api.pattern.PatternMatchContext;
@@ -189,15 +189,13 @@ protected void addErrorText(List<ITextComponent> textList) {
189189
@Override
190190
protected MultiblockUIFactory createUIFactory() {
191191
MultiblockFuelRecipeLogic recipeLogic = (MultiblockFuelRecipeLogic) recipeMapWorkable;
192+
boolean noRotor = getRotorHolder() == null;
192193
IntSyncValue efficiency = new IntSyncValue(
193-
() -> 0, null,
194-
() -> getRotorHolder().getRotorEfficiency(), null);
194+
() -> noRotor ? 0 : getRotorHolder().getRotorEfficiency(), null);
195195
IntSyncValue total = new IntSyncValue(
196-
() -> 0, null,
197-
() -> getRotorHolder().getTotalEfficiency(), null);
196+
() -> noRotor ? 0 : getRotorHolder().getTotalEfficiency(), null);
198197
IntSyncValue durability = new IntSyncValue(
199-
() -> 0, null,
200-
() -> getRotorHolder().getRotorDurabilityPercent(), null);
198+
() -> noRotor ? 0 : getRotorHolder().getRotorDurabilityPercent(), null);
201199
BooleanSyncValue rotorFree = new BooleanSyncValue(
202200
this::isRotorFaceFree, null);
203201
StringSyncValue fuelAmount = new StringSyncValue(recipeLogic::getRecipeFluidInputInfo, null);
@@ -210,6 +208,22 @@ protected MultiblockUIFactory createUIFactory() {
210208
.syncValue("dura", rotorFree)
211209
.syncValue("fuel_amount", fuelAmount)
212210
.syncValue("prev_duration", prevDuration)
211+
.customScreen(() -> new GregtechDisplayScreen(this)
212+
.padding(4)
213+
.energy(this::getMaxVoltage, recipeLogic::getRecipeEUt)
214+
.addLine(buffer -> {
215+
buffer.writeBoolean(isStructureFormed());
216+
if (isStructureFormed())
217+
buffer.writeInt(noRotor ? -1 : getRotorHolder().getTotalEfficiency());
218+
}, buffer -> {
219+
if (!buffer.readBoolean()) return null;
220+
int i = buffer.readInt();
221+
if (i < 0) return null;
222+
return KeyUtil.lang(TextFormatting.GRAY,
223+
"gregtech.multiblock.turbine.efficiency", i);
224+
})
225+
.fuelNeeded(recipeLogic::getRecipeFluidInputInfo, recipeLogic::getPreviousRecipeDuration)
226+
.status())
213227
.configureDisplayText(builder -> builder
214228
.setWorkingStatus(recipeLogic::isWorkingEnabled, recipeLogic::isActive)
215229
.addEnergyProductionLine(getMaxVoltage(), recipeLogic.getRecipeEUt())

0 commit comments

Comments
 (0)