Skip to content

Commit e982a6f

Browse files
committed
experimental container stack
1 parent ee984af commit e982a6f

15 files changed

Lines changed: 372 additions & 122 deletions

src/main/java/com/cleanroommc/modularui/CommonProxy.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import net.minecraftforge.common.config.Config;
1515
import net.minecraftforge.common.config.ConfigManager;
1616
import net.minecraftforge.event.RegistryEvent;
17-
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
1817
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
1918
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
2019
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
@@ -65,20 +64,6 @@ public void registerBlocks(RegistryEvent.Register<EntityEntry> event) {
6564
.build());
6665
}
6766

68-
@SubscribeEvent
69-
public void onOpenContainer(PlayerContainerEvent.Open event) {
70-
if (event.getContainer() instanceof ModularContainer container) {
71-
container.onModularContainerOpened();
72-
}
73-
}
74-
75-
@SubscribeEvent
76-
public void onCloseContainer(PlayerContainerEvent.Close event) {
77-
if (event.getContainer() instanceof ModularContainer container) {
78-
container.onModularContainerClosed();
79-
}
80-
}
81-
8267
@SubscribeEvent
8368
public void onConfigChange(ConfigChangedEvent.OnConfigChangedEvent event) {
8469
if (event.getModID().equals(ModularUI.ID)) {

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

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
import com.cleanroommc.modularui.ModularUI;
44
import com.cleanroommc.modularui.ModularUIConfig;
55
import com.cleanroommc.modularui.api.drawable.IKey;
6+
import com.cleanroommc.modularui.network.NetworkUtils;
67

78
import net.minecraft.client.Minecraft;
8-
import net.minecraft.client.entity.EntityPlayerSP;
99
import net.minecraft.client.gui.FontRenderer;
1010
import net.minecraft.client.gui.GuiScreen;
1111
import net.minecraft.client.util.ITooltipFlag;
1212
import net.minecraft.entity.player.EntityPlayer;
1313
import net.minecraft.item.ItemStack;
14-
import net.minecraft.network.play.client.CPacketCloseWindow;
1514
import net.minecraft.util.text.TextFormatting;
1615
import net.minecraftforge.fluids.Fluid;
1716
import net.minecraftforge.fluids.FluidRegistry;
@@ -30,36 +29,35 @@
3029
public class MCHelper {
3130

3231
public static boolean hasMc() {
33-
return getMc() != null;
32+
return NetworkUtils.isDedicatedClient() && getMc() != null;
3433
}
3534

35+
@SideOnly(Side.CLIENT)
3636
public static @Nullable Minecraft getMc() {
3737
return Minecraft.getMinecraft();
3838
}
3939

40+
@SideOnly(Side.CLIENT)
4041
public static @Nullable EntityPlayer getPlayer() {
4142
if (hasMc()) {
4243
return getMc().player;
4344
}
4445
return null;
4546
}
4647

48+
@SideOnly(Side.CLIENT)
4749
public static boolean closeScreen() {
4850
if (!hasMc()) return false;
49-
EntityPlayer player = getPlayer();
50-
if (player != null) {
51-
player.closeScreen();
52-
return true;
53-
}
5451
Minecraft.getMinecraft().displayGuiScreen(null);
5552
return false;
5653
}
5754

55+
@SideOnly(Side.CLIENT)
5856
public static void popScreen(boolean openParentOnClose, GuiScreen parent) {
5957
EntityPlayer player = MCHelper.getPlayer();
6058
if (player != null) {
61-
// container should not just be closed here, however this means the gui stack only works with client only screens (except the root)
62-
// TODO: figure out the necessity of a Container stack
59+
// container should not just be closed here
60+
// instead they are kept in a stack until all screens are closed
6361
if (openParentOnClose) {
6462
Minecraft.getMinecraft().displayGuiScreen(parent);
6563
} else {
@@ -72,13 +70,6 @@ public static void popScreen(boolean openParentOnClose, GuiScreen parent) {
7270
}
7371

7472
@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-
8273
public static boolean displayScreen(GuiScreen screen) {
8374
Minecraft mc = getMc();
8475
if (mc != null) {
@@ -88,11 +79,13 @@ public static boolean displayScreen(GuiScreen screen) {
8879
return false;
8980
}
9081

82+
@SideOnly(Side.CLIENT)
9183
public static GuiScreen getCurrentScreen() {
9284
Minecraft mc = getMc();
9385
return mc != null ? mc.currentScreen : null;
9486
}
9587

88+
@SideOnly(Side.CLIENT)
9689
public static FontRenderer getFontRenderer() {
9790
if (hasMc()) return getMc().fontRenderer;
9891
return null;

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,21 @@ public static <T extends GuiData> void open(@NotNull UIFactory<T> factory, @NotN
8888
int windowId = player.currentWindowId;
8989
PacketBuffer buffer = new PacketBuffer(Unpooled.buffer());
9090
factory.writeGuiData(guiData, buffer);
91-
ModularNetwork.SERVER.activate(windowId, msm);
92-
NetworkHandler.sendToPlayer(new OpenGuiPacket<>(windowId, factory, buffer), player);
91+
int nid = ModularNetwork.SERVER.activate(msm);
92+
NetworkHandler.sendToPlayer(new OpenGuiPacket<>(windowId, nid, factory, buffer), player);
9393
// open container // this mimics forge behaviour
9494
player.openContainer = container;
9595
player.openContainer.windowId = windowId;
9696
player.openContainer.addListener(player);
97+
// init mui syncer
98+
msm.onOpen();
9799
// finally invoke event
98100
MinecraftForge.EVENT_BUS.post(new PlayerContainerEvent.Open(player, container));
99101
}
100102

101103
@ApiStatus.Internal
102104
@SideOnly(Side.CLIENT)
103-
public static <T extends GuiData> void openFromClient(int windowId, @NotNull UIFactory<T> factory, @NotNull PacketBuffer data, @NotNull EntityPlayerSP player) {
105+
public static <T extends GuiData> void openFromClient(int windowId, int networkId, @NotNull UIFactory<T> factory, @NotNull PacketBuffer data, @NotNull EntityPlayerSP player) {
104106
T guiData = factory.readGuiData(player, data);
105107
UISettings settings = new UISettings();
106108
settings.defaultCanInteractWith(factory, guiData);
@@ -118,16 +120,19 @@ public static <T extends GuiData> void openFromClient(int windowId, @NotNull UIF
118120
}
119121
if (guiContainer.inventorySlots != container) throw new IllegalStateException("Custom Containers are not yet allowed!");
120122
guiContainer.inventorySlots.windowId = windowId;
121-
ModularNetwork.CLIENT.activate(windowId, msm);
123+
ModularNetwork.CLIENT.activate(networkId, msm);
122124
MCHelper.displayScreen(wrapper.getGuiScreen());
123125
player.openContainer = guiContainer.inventorySlots;
126+
msm.onOpen();
124127
}
125128

126129
@SideOnly(Side.CLIENT)
127130
public static <T extends GuiData> void openFromClient(@NotNull UIFactory<T> factory, @NotNull T guiData) {
131+
// notify server to open the gui
132+
// server will send packet back to actually open the gui
128133
PacketBuffer buffer = new PacketBuffer(Unpooled.buffer());
129134
factory.writeGuiData(guiData, buffer);
130-
NetworkHandler.sendToServer(new OpenGuiPacket<>(0, factory, buffer));
135+
NetworkHandler.sendToServer(new OpenGuiPacket<>(0, 0, factory, buffer));
131136
}
132137

133138
@SideOnly(Side.CLIENT)
Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,97 @@
11
package com.cleanroommc.modularui.network;
22

3-
import com.cleanroommc.modularui.ModularUI;
4-
import com.cleanroommc.modularui.network.packets.PacketSyncHandler;
53
import com.cleanroommc.modularui.value.sync.ModularSyncManager;
6-
import com.cleanroommc.modularui.value.sync.SyncHandler;
74

5+
import net.minecraft.client.Minecraft;
6+
import net.minecraft.client.entity.EntityPlayerSP;
87
import net.minecraft.entity.player.EntityPlayer;
98
import net.minecraft.entity.player.EntityPlayerMP;
10-
import net.minecraft.network.PacketBuffer;
9+
import net.minecraft.item.ItemStack;
1110
import net.minecraftforge.fml.relauncher.Side;
1211
import net.minecraftforge.fml.relauncher.SideOnly;
1312

14-
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
15-
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
16-
17-
import java.io.IOException;
13+
import org.jetbrains.annotations.ApiStatus;
1814

15+
@ApiStatus.Experimental
1916
public abstract class ModularNetwork {
2017

2118
// These need to be separate instances, otherwise they would access the same maps in singleplayer.
22-
@SideOnly(Side.CLIENT)
23-
public static final ModularNetwork CLIENT = new ModularNetwork(true) {
24-
@Override
25-
protected void sendPacket(IPacket packet, EntityPlayer player) {
26-
NetworkHandler.sendToServer(packet);
27-
}
28-
};
29-
public static final ModularNetwork SERVER = new ModularNetwork(false) {
30-
@Override
31-
protected void sendPacket(IPacket packet, EntityPlayer player) {
32-
NetworkHandler.sendToPlayer(packet, (EntityPlayerMP) player);
33-
}
34-
};
19+
// You have to make sure you are choosing the logical side you are currently on otherwise you can mess things badly, since
20+
// there is no validation.
21+
public static final Client CLIENT = new Client();
22+
public static final Server SERVER = new Server();
3523

36-
public static ModularNetwork get(boolean client) {
24+
public static ModularNetworkSide get(boolean client) {
3725
return client ? CLIENT : SERVER;
3826
}
3927

40-
public static ModularNetwork get(Side side) {
28+
public static ModularNetworkSide get(Side side) {
4129
return side.isClient() ? CLIENT : SERVER;
4230
}
4331

44-
public static ModularNetwork get(EntityPlayer player) {
32+
public static ModularNetworkSide get(EntityPlayer player) {
4533
return get(NetworkUtils.isClient(player));
4634
}
4735

48-
private final boolean client;
49-
private final Int2ReferenceOpenHashMap<ModularSyncManager> activeScreens = new Int2ReferenceOpenHashMap<>();
50-
private final Reference2IntOpenHashMap<ModularSyncManager> inverseActiveScreens = new Reference2IntOpenHashMap<>();
36+
public static final class Client extends ModularNetworkSide {
5137

52-
private ModularNetwork(boolean client) {
53-
this.client = client;
54-
}
38+
private Client() {
39+
super(true);
40+
}
5541

56-
public boolean isClient() {
57-
return client;
58-
}
42+
public void activate(int nid, ModularSyncManager msm) {
43+
activateInternal(nid, msm);
44+
}
5945

60-
protected abstract void sendPacket(IPacket packet, EntityPlayer player);
46+
@Override
47+
void sendPacket(IPacket packet, EntityPlayer player) {
48+
NetworkHandler.sendToServer(packet);
49+
}
6150

62-
public void activate(int networkId, ModularSyncManager manager) {
63-
if (activeScreens.containsKey(networkId)) throw new IllegalStateException("Network ID " + networkId + " is already active.");
64-
activeScreens.put(networkId, manager);
65-
inverseActiveScreens.put(manager, networkId);
66-
}
51+
@Override
52+
void closeContainer(EntityPlayer player) {
53+
// mimics EntityPlayerSP.closeScreenAndDropStack() but without closing the screen
54+
player.inventory.setItemStack(ItemStack.EMPTY);
55+
player.openContainer = player.inventoryContainer;
56+
}
6757

68-
public void deactivate(ModularSyncManager manager) {
69-
int id = inverseActiveScreens.removeInt(manager);
70-
activeScreens.remove(id);
71-
}
58+
@SideOnly(Side.CLIENT)
59+
public void closeContainer(int networkId, boolean dispose, EntityPlayerSP player) {
60+
closeContainer(networkId, dispose, player, true);
61+
}
7262

73-
public void receivePacket(PacketSyncHandler packet) {
74-
ModularSyncManager msm = activeScreens.get(packet.networkId);
75-
if (msm == null) return; // silently discard packets for inactive screens
76-
try {
77-
int id = packet.action ? 0 : packet.packet.readVarInt();
78-
msm.receiveWidgetUpdate(packet.panel, packet.key, packet.action, id, packet.packet);
79-
} catch (IndexOutOfBoundsException e) {
80-
ModularUI.LOGGER.error("Failed to read packet for sync handler {} in panel {}", packet.key, packet.panel);
81-
} catch (IOException e) {
82-
ModularUI.LOGGER.throwing(e);
63+
@SideOnly(Side.CLIENT)
64+
public void closeAll() {
65+
closeAll(Minecraft.getMinecraft().player);
8366
}
8467
}
8568

86-
public void sendSyncHandlerPacket(String panel, SyncHandler syncHandler, PacketBuffer buffer, EntityPlayer player) {
87-
ModularSyncManager msm = syncHandler.getSyncManager().getModularSyncManager();
88-
if (!inverseActiveScreens.containsKey(msm)) return;
89-
int id = inverseActiveScreens.getInt(msm);
90-
sendPacket(new PacketSyncHandler(id, panel, syncHandler.getKey(), false, buffer), player);
91-
}
69+
public static final class Server extends ModularNetworkSide {
70+
71+
private int nextId = -1;
72+
73+
private Server() {
74+
super(false);
75+
}
76+
77+
public int activate(ModularSyncManager msm) {
78+
if (++nextId > 100_000) nextId = 0;
79+
activateInternal(nextId, msm);
80+
return nextId;
81+
}
9282

93-
public void sendActionPacket(ModularSyncManager msm, String panel, String key, PacketBuffer buffer, EntityPlayer player) {
94-
if (!inverseActiveScreens.containsKey(msm)) return;
95-
int id = inverseActiveScreens.getInt(msm);
96-
sendPacket(new PacketSyncHandler(id, panel, key, true, buffer), player);
83+
@Override
84+
protected void sendPacket(IPacket packet, EntityPlayer player) {
85+
NetworkHandler.sendToPlayer(packet, (EntityPlayerMP) player);
86+
}
87+
88+
@Override
89+
void closeContainer(EntityPlayer player) {
90+
((EntityPlayerMP) player).closeContainer();
91+
}
92+
93+
public void closeContainer(int networkId, boolean dispose, EntityPlayerMP player) {
94+
closeContainer(networkId, dispose, player, true);
95+
}
9796
}
9897
}

0 commit comments

Comments
 (0)