Skip to content

Commit 8b0d7f6

Browse files
committed
finalize screen state rework
1 parent 51a6f51 commit 8b0d7f6

9 files changed

Lines changed: 156 additions & 103 deletions

File tree

src/main/java/com/cleanroommc/modularui/api/MCHelper.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
import com.cleanroommc.modularui.api.drawable.IKey;
66

77
import net.minecraft.client.Minecraft;
8+
import net.minecraft.client.entity.EntityPlayerSP;
89
import net.minecraft.client.gui.FontRenderer;
910
import net.minecraft.client.gui.GuiScreen;
1011
import net.minecraft.client.util.ITooltipFlag;
1112
import net.minecraft.entity.player.EntityPlayer;
1213
import net.minecraft.item.ItemStack;
14+
import net.minecraft.network.play.client.CPacketCloseWindow;
1315
import net.minecraft.util.text.TextFormatting;
1416
import net.minecraftforge.fluids.Fluid;
1517
import net.minecraftforge.fluids.FluidRegistry;
1618
import net.minecraftforge.fluids.FluidStack;
1719
import net.minecraftforge.fml.common.Loader;
1820
import net.minecraftforge.fml.common.ModContainer;
21+
import net.minecraftforge.fml.relauncher.Side;
22+
import net.minecraftforge.fml.relauncher.SideOnly;
1923

2024
import org.jetbrains.annotations.NotNull;
2125
import org.jetbrains.annotations.Nullable;
@@ -51,6 +55,30 @@ public static boolean closeScreen() {
5155
return false;
5256
}
5357

58+
public static void popScreen(boolean openParentOnClose, GuiScreen parent) {
59+
EntityPlayer player = MCHelper.getPlayer();
60+
if (player != null) {
61+
// TODO: should we really close container here?
62+
prepareCloseContainer(player);
63+
if (openParentOnClose) {
64+
Minecraft.getMinecraft().displayGuiScreen(parent);
65+
} else {
66+
Minecraft.getMinecraft().displayGuiScreen(null);
67+
}
68+
} else {
69+
// we are currently not in a world and want to display the previous screen
70+
Minecraft.getMinecraft().displayGuiScreen(parent);
71+
}
72+
}
73+
74+
@SideOnly(Side.CLIENT)
75+
private static void prepareCloseContainer(EntityPlayer entityPlayer) {
76+
EntityPlayerSP player = (EntityPlayerSP) entityPlayer;
77+
player.connection.sendPacket(new CPacketCloseWindow(player.openContainer.windowId));
78+
player.openContainer = player.inventoryContainer;
79+
player.inventory.setItemStack(ItemStack.EMPTY);
80+
}
81+
5482
public static boolean displayScreen(GuiScreen screen) {
5583
Minecraft mc = getMc();
5684
if (mc != null) {

src/main/java/com/cleanroommc/modularui/factory/GuiManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ public static <T extends GuiData> void openFromClient(@NotNull UIFactory<T> fact
126126

127127
@SideOnly(Side.CLIENT)
128128
static void openScreen(ModularScreen screen, UISettings settings) {
129+
if (screen.getScreenWrapper() != null && MCHelper.getCurrentScreen() == screen.getScreenWrapper().getGuiScreen()) {
130+
// already open
131+
return;
132+
}
129133
screen.getContext().setSettings(settings);
130134
GuiScreen guiScreen;
131135
if (settings.hasContainer()) {

src/main/java/com/cleanroommc/modularui/overlay/OverlayStack.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,17 @@ public static void open(ModularScreen screen) {
7777

7878
public static void close(ModularScreen screen) {
7979
if (overlay.remove(screen)) {
80-
screen.onCloseParent();
80+
// TODO: Maybe not always dispose similar to normal screens
81+
screen.getPanelManager().closeAll();
82+
screen.getPanelManager().dispose();
8183
}
8284
}
8385

8486
static void closeAll() {
8587
for (int i = overlay.size() - 1; i >= 0; i--) {
8688
ModularScreen screen = overlay.remove(i);
87-
screen.onCloseParent();
89+
screen.getPanelManager().closeAll();
90+
screen.getPanelManager().dispose();
8891
}
8992
}
9093

src/main/java/com/cleanroommc/modularui/screen/ClientScreenHandler.java

Lines changed: 83 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@
5454
import net.minecraftforge.fml.relauncher.Side;
5555
import net.minecraftforge.fml.relauncher.SideOnly;
5656

57+
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
5758
import org.jetbrains.annotations.ApiStatus;
5859
import org.jetbrains.annotations.Nullable;
60+
import org.jetbrains.annotations.UnmodifiableView;
5961
import org.lwjgl.input.Keyboard;
6062
import org.lwjgl.input.Mouse;
6163
import org.lwjgl.opengl.GL11;
@@ -78,49 +80,18 @@ public class ClientScreenHandler {
7880
private static long ticks = 0L;
7981

8082
private static IMuiScreen lastMui;
83+
private static final ObjectArrayList<IMuiScreen> muiStack = new ObjectArrayList<>(8);
8184

8285
// we need to know the actual gui and not some fake screen some other mod overwrites
8386
@SubscribeEvent(priority = EventPriority.LOWEST)
84-
public void onGuiOpen(GuiOpenEvent event) {
87+
public void onGuiChange(GuiOpenEvent event) {
8588
onGuiChanged(getMCScreen(), event.getGui());
8689
}
8790

88-
private static void onGuiChanged(GuiScreen oldScreen, GuiScreen newScreen) {
89-
if (oldScreen == newScreen) return;
90-
defaultContext.reset();
91-
92-
GuiScreen lastParent = null;
93-
if (lastMui != null) {
94-
if (newScreen == lastMui) {
95-
// reopen
96-
return;
97-
}
98-
lastParent = lastMui.getScreen().getContext().getParentScreen();
99-
lastMui.getScreen().onCloseParent();
100-
lastMui = null;
101-
currentScreen = null;
102-
lastChar = null;
103-
}
104-
105-
if (newScreen instanceof IMuiScreen muiScreen) {
106-
lastMui = muiScreen;
107-
currentScreen = muiScreen.getScreen();
108-
GuiScreen parent = oldScreen;
109-
if (lastParent == parent && parent instanceof IMuiScreen oldMuiScreen) {
110-
parent = oldMuiScreen.getScreen().getContext().getParentScreen();
111-
}
112-
currentScreen.getContext().setParentScreen(parent);
113-
fpsCounter.reset();
114-
}
115-
116-
GuiErrorHandler.INSTANCE.clear();
117-
OverlayManager.onGuiOpen(newScreen);
118-
}
119-
12091
@SubscribeEvent
12192
public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
12293
defaultContext.updateScreenArea(event.getGui().width, event.getGui().height);
123-
if (checkGui(event.getGui())) {
94+
if (validateGui(event.getGui())) {
12495
currentScreen.onResize(event.getGui().width, event.getGui().height);
12596
}
12697
OverlayStack.foreach(ms -> ms.onResize(event.getGui().width, event.getGui().height), false);
@@ -140,7 +111,7 @@ public void onGuiInputLow(GuiScreenEvent.KeyboardInputEvent.Pre event) throws IO
140111
}
141112

142113
private static void inputEvent(GuiScreenEvent.KeyboardInputEvent.Pre event, InputPhase phase) throws IOException {
143-
if (checkGui(event.getGui())) currentScreen.getContext().updateEventState();
114+
if (validateGui(event.getGui())) currentScreen.getContext().updateEventState();
144115
if (handleKeyboardInput(currentScreen, event.getGui(), phase)) {
145116
event.setCanceled(true);
146117
}
@@ -150,7 +121,7 @@ private static void inputEvent(GuiScreenEvent.KeyboardInputEvent.Pre event, Inpu
150121
@SubscribeEvent(priority = EventPriority.HIGH)
151122
public void onGuiInputHigh(GuiScreenEvent.MouseInputEvent.Pre event) throws IOException {
152123
defaultContext.updateEventState();
153-
if (checkGui(event.getGui())) currentScreen.getContext().updateEventState();
124+
if (validateGui(event.getGui())) currentScreen.getContext().updateEventState();
154125
if (handleMouseInput(Mouse.getEventButton(), currentScreen, event.getGui())) {
155126
Platform.unFocusRecipeViewer();
156127
event.setCanceled(true);
@@ -159,7 +130,7 @@ public void onGuiInputHigh(GuiScreenEvent.MouseInputEvent.Pre event) throws IOEx
159130
int w = Mouse.getEventDWheel();
160131
if (w == 0) return;
161132
UpOrDown upOrDown = w > 0 ? UpOrDown.UP : UpOrDown.DOWN;
162-
checkGui(event.getGui());
133+
validateGui(event.getGui());
163134
if (doAction(currentScreen, ms -> ms.onMouseScroll(upOrDown, Math.abs(w)))) {
164135
event.setCanceled(true);
165136
}
@@ -171,7 +142,7 @@ public void onGuiDraw(GuiScreenEvent.DrawScreenEvent.Pre event) {
171142
float pt = event.getRenderPartialTicks();
172143
defaultContext.updateState(mx, my, pt);
173144
defaultContext.reset();
174-
if (checkGui(event.getGui())) {
145+
if (validateGui(event.getGui())) {
175146
currentScreen.getContext().updateState(mx, my, pt);
176147
drawScreen(currentScreen, currentScreen.getScreenWrapper().getGuiScreen(), mx, my, pt);
177148
event.setCanceled(true);
@@ -190,7 +161,7 @@ public void onTick(TickEvent.ClientTickEvent event) {
190161
if (event.phase == TickEvent.Phase.END) {
191162
OverlayStack.onTick();
192163
defaultContext.tick();
193-
if (checkGui()) {
164+
if (validateGui()) {
194165
currentScreen.onUpdate();
195166
}
196167
ticks++;
@@ -214,6 +185,59 @@ public static void onFrameUpdate() {
214185
if (currentScreen != null) currentScreen.onFrameUpdate();
215186
}
216187

188+
private static void onGuiChanged(GuiScreen oldScreen, GuiScreen newScreen) {
189+
if (oldScreen == newScreen) return;
190+
defaultContext.reset();
191+
fpsCounter.reset();
192+
GuiErrorHandler.INSTANCE.clear();
193+
194+
IMuiScreen lastLastMui = lastMui;
195+
if (lastMui != null) {
196+
// called on open and close
197+
// invalidate last mui screen, but keep it in stack
198+
invalidateCurrentScreen();
199+
}
200+
201+
if (newScreen instanceof IMuiScreen muiScreen) {
202+
lastMui = muiScreen;
203+
currentScreen = muiScreen.getScreen();
204+
muiStack.remove(muiScreen);
205+
muiStack.add(muiScreen); // put screen to the top of the stack
206+
GuiScreen lastParent = lastLastMui != null ? lastLastMui.getScreen().getContext().getParentScreen() : null;
207+
if (lastParent != muiScreen) {
208+
// new screen in the stack
209+
currentScreen.getContext().setParentScreen(oldScreen);
210+
} else {
211+
// last parent is equal to new screen -> effectively popping the current screen from the stack
212+
// the current screen will disconnect from the stack and therefore need to dispose it
213+
muiStack.remove(lastLastMui);
214+
lastLastMui.getScreen().getPanelManager().dispose();
215+
}
216+
} else if (newScreen == null) {
217+
// closing -> clear stack and dispose every screen
218+
invalidateMuiStack();
219+
}
220+
221+
OverlayManager.onGuiOpen(newScreen);
222+
}
223+
224+
private static void invalidateCurrentScreen() {
225+
// reset mouse inputs, relevant when screen gets reopened
226+
if (lastMui != null) {
227+
((GuiScreenAccessor) lastMui.getGuiScreen()).setEventButton(-1);
228+
((GuiScreenAccessor) lastMui.getGuiScreen()).setLastMouseEvent(-1);
229+
lastMui.getScreen().getPanelManager().closeAll();
230+
lastMui = null;
231+
}
232+
currentScreen = null;
233+
lastChar = null;
234+
}
235+
236+
private static void invalidateMuiStack() {
237+
muiStack.forEach(muiScreen -> muiScreen.getScreen().getPanelManager().dispose());
238+
muiStack.clear();
239+
}
240+
217241
private static boolean doAction(@Nullable ModularScreen muiScreen, Predicate<ModularScreen> action) {
218242
return OverlayStack.interact(action, true) || (muiScreen != null && action.test(muiScreen));
219243
}
@@ -312,7 +336,7 @@ public static void dragSlot(long timeSinceLastClick) {
312336

313337
public static void clickSlot(ModularScreen ms, Slot slot) {
314338
GuiScreen screen = ms.getScreenWrapper().getGuiScreen();
315-
if (screen instanceof GuiScreenAccessor acc && screen instanceof IClickableGuiContainer clickableGuiContainer && checkGui(screen)) {
339+
if (screen instanceof GuiScreenAccessor acc && screen instanceof IClickableGuiContainer clickableGuiContainer && validateGui(screen)) {
316340
ModularGuiContext ctx = ms.getContext();
317341
List<GuiButton> buttonList = acc.getButtonList();
318342
try {
@@ -502,7 +526,7 @@ public static void drawDebugScreen(@Nullable ModularScreen muiScreen, @Nullable
502526
fpsCounter.onDraw();
503527
if (!ModularUIConfig.guiDebugMode) return;
504528
if (muiScreen == null) {
505-
if (checkGui()) {
529+
if (validateGui()) {
506530
muiScreen = currentScreen;
507531
} else {
508532
if (fallback == null) return;
@@ -614,16 +638,27 @@ public static ModularScreen getMuiScreen() {
614638
return currentScreen;
615639
}
616640

617-
private static boolean checkGui() {
618-
return MCHelper.hasMc() && checkGui(Minecraft.getMinecraft().currentScreen);
641+
@UnmodifiableView
642+
public static List<IMuiScreen> getMuiStack() {
643+
return Collections.unmodifiableList(muiStack);
644+
}
645+
646+
private static boolean validateGui() {
647+
return MCHelper.hasMc() && validateGui(Minecraft.getMinecraft().currentScreen);
619648
}
620649

621-
private static boolean checkGui(GuiScreen screen) {
622-
if (!MCHelper.hasMc() || currentScreen == null || !(screen instanceof IMuiScreen muiScreen)) return false;
650+
private static boolean validateGui(GuiScreen screen) {
651+
if (!MCHelper.hasMc() || currentScreen == null || !(screen instanceof IMuiScreen muiScreen)) {
652+
// no mui screen currently open
653+
return false;
654+
}
623655
if (screen != Minecraft.getMinecraft().currentScreen || muiScreen.getScreen() != currentScreen) {
656+
// mui screen doesn't match the events screen -> invalidate
624657
defaultContext.reset();
625-
currentScreen = null;
626-
lastChar = null;
658+
invalidateCurrentScreen();
659+
if (MCHelper.getCurrentScreen() == null) {
660+
invalidateMuiStack();
661+
}
627662
return false;
628663
}
629664
return true;
@@ -634,7 +669,7 @@ public static GuiContext getDefaultContext() {
634669
}
635670

636671
public static GuiContext getBestContext() {
637-
if (checkGui()) {
672+
if (validateGui()) {
638673
return currentScreen.getContext();
639674
}
640675
return defaultContext;

src/main/java/com/cleanroommc/modularui/screen/GuiContainerWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, i
3636
public boolean doesGuiPauseGame() {
3737
return this.screen != null && this.screen.doesPauseGame();
3838
}
39+
40+
@Override
41+
public String toString() {
42+
return "Wrapper(" + getScreen() + ")";
43+
}
3944
}

src/main/java/com/cleanroommc/modularui/screen/GuiScreenWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ public void drawWorldBackground(int tint) {
3333
public boolean doesGuiPauseGame() {
3434
return this.screen == null || this.screen.doesPauseGame();
3535
}
36+
37+
@Override
38+
public String toString() {
39+
return "Wrapper(" + getScreen() + ")";
40+
}
3641
}

src/main/java/com/cleanroommc/modularui/screen/ModularPanel.java

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@
3434
import com.cleanroommc.neverenoughanimations.NEAConfig;
3535

3636
import net.minecraft.client.Minecraft;
37-
import net.minecraft.client.entity.EntityPlayerSP;
38-
import net.minecraft.entity.player.EntityPlayer;
39-
import net.minecraft.item.ItemStack;
40-
import net.minecraft.network.play.client.CPacketCloseWindow;
41-
import net.minecraftforge.fml.relauncher.Side;
42-
import net.minecraftforge.fml.relauncher.SideOnly;
4337

4438
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
4539
import mezz.jei.gui.ghost.GhostIngredientDrag;
@@ -137,18 +131,7 @@ public void closeIfOpen() {
137131
closeSubPanels();
138132
if (isMainPanel()) {
139133
// close screen and let NEA animation
140-
EntityPlayer player = MCHelper.getPlayer();
141-
if (player != null) {
142-
prepareCloseContainer(player);
143-
if (getScreen().isOpenParentOnClose()) {
144-
Minecraft.getMinecraft().displayGuiScreen(getContext().getParentScreen());
145-
} else {
146-
Minecraft.getMinecraft().displayGuiScreen(null);
147-
}
148-
} else {
149-
// we are currently not in a world and want to display the previous screen
150-
Minecraft.getMinecraft().displayGuiScreen(getContext().getParentScreen());
151-
}
134+
MCHelper.popScreen(getScreen().isOpenParentOnClose(), getContext().getParentScreen());
152135
return;
153136
}
154137
if (!shouldAnimate()) {
@@ -170,14 +153,6 @@ public void closeIfOpen() {
170153
}
171154
}
172155

173-
@SideOnly(Side.CLIENT)
174-
private static void prepareCloseContainer(EntityPlayer entityPlayer) {
175-
EntityPlayerSP player = (EntityPlayerSP) entityPlayer;
176-
player.connection.sendPacket(new CPacketCloseWindow(player.openContainer.windowId));
177-
player.openContainer = player.inventoryContainer;
178-
player.inventory.setItemStack(ItemStack.EMPTY);
179-
}
180-
181156
protected void closeSubPanels() {
182157
if (this.panelHandler != null) {
183158
this.panelHandler.closeSubPanels();

0 commit comments

Comments
 (0)