diff --git a/src/main/java/com/glodblock/github/FluidCraft.java b/src/main/java/com/glodblock/github/FluidCraft.java index 71435ba7..1cd4f76a 100644 --- a/src/main/java/com/glodblock/github/FluidCraft.java +++ b/src/main/java/com/glodblock/github/FluidCraft.java @@ -14,6 +14,7 @@ import com.glodblock.github.loader.ChannelLoader; import com.glodblock.github.loader.ItemAndBlockHolder; import com.glodblock.github.loader.RecipeLoader; import com.glodblock.github.loader.filter.FluidFilter; +import com.glodblock.github.network.SPacketMEUpdateBuffer; import com.glodblock.github.proxy.CommonProxy; import com.glodblock.github.util.ModAndClassUtil; @@ -82,6 +83,16 @@ public class FluidCraft { proxy.postInit(event); } + @Mod.EventHandler + public void onServerStart(FMLServerStartingEvent event) { + SPacketMEUpdateBuffer.init(); + } + + @Mod.EventHandler + public void onServerStop(FMLServerStoppedEvent event) { + SPacketMEUpdateBuffer.disable(); + } + @Mod.EventHandler public void onLoadComplete(FMLLoadCompleteEvent event) {} diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidMonitor.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidMonitor.java index aebc0dc4..9474fae9 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidMonitor.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerFluidMonitor.java @@ -1,7 +1,8 @@ package com.glodblock.github.client.gui.container; -import java.nio.BufferOverflowException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import net.minecraft.entity.player.EntityPlayer; @@ -43,7 +44,7 @@ import com.glodblock.github.client.gui.container.base.FCContainerMonitor; import com.glodblock.github.common.item.ItemFluidDrop; import com.glodblock.github.network.CPacketFluidUpdate; import com.glodblock.github.network.SPacketFluidUpdate; -import com.glodblock.github.network.SPacketMEFluidInvUpdate; +import com.glodblock.github.network.SPacketMEUpdateBuffer; import com.glodblock.github.util.Util; public class ContainerFluidMonitor extends FCContainerMonitor { @@ -126,33 +127,22 @@ public class ContainerFluidMonitor extends FCContainerMonitor { protected void processItemList() { if (!this.fluids.isEmpty()) { final IItemList monitorCache = this.monitor.getStorageList(); - SPacketMEFluidInvUpdate packet = new SPacketMEFluidInvUpdate(); + List toSend = new ArrayList<>(); for (final IAEFluidStack is : this.fluids) { final IAEFluidStack send = monitorCache.findPrecise(is); - try { - if (send != null) { - packet.appendFluid(send); - } else { - is.setStackSize(0); - packet.appendFluid(is); - } - } catch (BufferOverflowException e) { - for (final Object c : this.crafters) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); - } - packet = new SPacketMEFluidInvUpdate(); - if (send != null) { - packet.appendFluid(send); - } else { - is.setStackSize(0); - packet.appendFluid(is); - } - + if (send != null) { + toSend.add(send); + } else { + is.setStackSize(0); + toSend.add(is); } } for (final Object c : this.crafters) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); + if (c instanceof EntityPlayerMP) { + SPacketMEUpdateBuffer.scheduleFluidUpdate((EntityPlayerMP) c, toSend); + } } + this.fluids.resetStatus(); } } @@ -160,17 +150,11 @@ public class ContainerFluidMonitor extends FCContainerMonitor { protected void queueInventory(final ICrafting c) { if (Platform.isServer() && c instanceof EntityPlayerMP && this.monitor != null) { final IItemList monitorCache = this.monitor.getStorageList(); - SPacketMEFluidInvUpdate packet = new SPacketMEFluidInvUpdate(); + List toSend = new ArrayList<>(); for (final IAEFluidStack is : monitorCache) { - try { - packet.appendFluid(is); - } catch (BufferOverflowException e) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); - packet = new SPacketMEFluidInvUpdate(); - packet.appendFluid(is); - } + toSend.add(is); } - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); + SPacketMEUpdateBuffer.scheduleFluidUpdate((EntityPlayerMP) c, toSend); } } diff --git a/src/main/java/com/glodblock/github/client/gui/container/ContainerItemMonitor.java b/src/main/java/com/glodblock/github/client/gui/container/ContainerItemMonitor.java index acad6098..6cba6ea5 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/ContainerItemMonitor.java +++ b/src/main/java/com/glodblock/github/client/gui/container/ContainerItemMonitor.java @@ -1,6 +1,7 @@ package com.glodblock.github.client.gui.container; -import java.nio.BufferOverflowException; +import java.util.ArrayList; +import java.util.List; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -25,9 +26,8 @@ import appeng.container.slot.SlotRestrictedInput; import appeng.me.helpers.ChannelPowerSrc; import appeng.util.Platform; -import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.base.FCContainerMonitor; -import com.glodblock.github.network.SPacketMEItemInvUpdate; +import com.glodblock.github.network.SPacketMEUpdateBuffer; public class ContainerItemMonitor extends FCContainerMonitor { @@ -95,34 +95,19 @@ public class ContainerItemMonitor extends FCContainerMonitor { protected void processItemList() { if (!this.items.isEmpty()) { final IItemList monitorCache = this.monitor.getStorageList(); - SPacketMEItemInvUpdate packet = new SPacketMEItemInvUpdate(); + List toSend = new ArrayList<>(); for (final IAEItemStack is : this.items) { final IAEItemStack send = monitorCache.findPrecise(is); - try { - if (send != null) { - packet.appendItem(send); - } else { - is.setStackSize(0); - packet.appendItem(is); - } - } catch (BufferOverflowException e) { - for (final Object c : this.crafters) { - if (c instanceof EntityPlayerMP) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); - } - } - packet = new SPacketMEItemInvUpdate(); - if (send != null) { - packet.appendItem(send); - } else { - is.setStackSize(0); - packet.appendItem(is); - } + if (send != null) { + toSend.add(send); + } else { + is.setStackSize(0); + toSend.add(is); } } for (final Object c : this.crafters) { - if (c instanceof EntityPlayerMP) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); + if (c instanceof EntityPlayer) { + SPacketMEUpdateBuffer.scheduleItemUpdate((EntityPlayerMP) c, toSend); } } this.items.resetStatus(); @@ -133,17 +118,11 @@ public class ContainerItemMonitor extends FCContainerMonitor { protected void queueInventory(final ICrafting c) { if (Platform.isServer() && c instanceof EntityPlayer && this.monitor != null) { final IItemList monitorCache = this.monitor.getStorageList(); - SPacketMEItemInvUpdate packet = new SPacketMEItemInvUpdate(); + List toSend = new ArrayList<>(); for (final IAEItemStack is : monitorCache) { - try { - packet.appendItem(is); - } catch (BufferOverflowException e) { - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); - packet = new SPacketMEItemInvUpdate(); - packet.appendItem(is); - } + toSend.add(is); } - FluidCraft.proxy.netHandler.sendTo(packet, (EntityPlayerMP) c); + SPacketMEUpdateBuffer.scheduleItemUpdate((EntityPlayerMP) c, toSend); } } @@ -152,6 +131,9 @@ public class ContainerItemMonitor extends FCContainerMonitor { super.removeCraftingFromCrafters(c); if (this.crafters.isEmpty() && this.monitor != null) { this.monitor.removeListener(this); + if (c instanceof EntityPlayerMP) { + SPacketMEUpdateBuffer.clear((EntityPlayerMP) c); + } } } diff --git a/src/main/java/com/glodblock/github/client/gui/container/base/FCContainerMonitor.java b/src/main/java/com/glodblock/github/client/gui/container/base/FCContainerMonitor.java index a2cd9fb7..407d0115 100644 --- a/src/main/java/com/glodblock/github/client/gui/container/base/FCContainerMonitor.java +++ b/src/main/java/com/glodblock/github/client/gui/container/base/FCContainerMonitor.java @@ -30,6 +30,7 @@ import appeng.util.IConfigManagerHost; import appeng.util.Platform; import com.glodblock.github.inventory.item.IWirelessTerminal; +import com.glodblock.github.network.SPacketMEUpdateBuffer; public abstract class FCContainerMonitor> extends FCBaseContainer implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver { @@ -158,6 +159,10 @@ public abstract class FCContainerMonitor> extends FCBaseCo super.onContainerClosed(player); if (this.monitor != null) { this.monitor.removeListener(this); + if (player instanceof EntityPlayerMP && Platform.isServer()) { + SPacketMEUpdateBuffer.clear((EntityPlayerMP) player); + } + } } diff --git a/src/main/java/com/glodblock/github/common/Config.java b/src/main/java/com/glodblock/github/common/Config.java index 573c5a3f..01ee7ca7 100644 --- a/src/main/java/com/glodblock/github/common/Config.java +++ b/src/main/java/com/glodblock/github/common/Config.java @@ -18,6 +18,7 @@ public class Config { public static boolean blacklistEssentiaGas; public static double portableCellBattery; public static int packetSize; + public static int packetRate; public static void run() { loadCategory(); @@ -55,6 +56,10 @@ public class Config { packetSize = Config.get("Fluid Craft for AE2", "packetSize", 256, "Number of items to be sent per packet") .getInt(); if (packetSize <= 0) packetSize = 256; + packetRate = Config + .get("Fluid Craft for AE2", "packetRate", 50, "Period at which packets are dispatched, in ms.") + .getInt(); + if (packetRate <= 0) packetRate = 50; if (Config.hasChanged()) Config.save(); } diff --git a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java index 76a009bd..55c80d4d 100644 --- a/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java +++ b/src/main/java/com/glodblock/github/network/CPacketLevelMaintainer.java @@ -1,5 +1,8 @@ package com.glodblock.github.network; +import java.util.ArrayList; +import java.util.List; + import javax.annotation.Nullable; import net.minecraft.entity.player.EntityPlayerMP; @@ -9,7 +12,6 @@ import net.minecraft.nbt.NBTTagCompound; import appeng.api.storage.data.IAEItemStack; import appeng.util.item.AEItemStack; -import com.glodblock.github.FluidCraft; import com.glodblock.github.client.gui.container.ContainerLevelMaintainer; import com.glodblock.github.common.tile.TileLevelMaintainer; @@ -88,7 +90,7 @@ public class CPacketLevelMaintainer implements IMessage { public static class Handler implements IMessageHandler { private void refresh(ContainerLevelMaintainer cca, EntityPlayerMP player) { - SPacketMEItemInvUpdate packet = new SPacketMEItemInvUpdate(); + List toSend = new ArrayList<>(TileLevelMaintainer.REQ_COUNT); for (int i = 0; i < TileLevelMaintainer.REQ_COUNT; i++) { IAEItemStack is = cca.getTile().requests.getRequestQtyStack(i); IAEItemStack is1 = cca.getTile().requests.getRequestBatches().getStack(i); @@ -96,7 +98,7 @@ public class CPacketLevelMaintainer implements IMessage { if (is1 != null) { NBTTagCompound data; data = is1.getItemStack().getTagCompound(); - packet.appendItem( + toSend.add( setTag( is, is1.getStackSize(), @@ -104,11 +106,11 @@ public class CPacketLevelMaintainer implements IMessage { data.getBoolean("Enable"), cca.getTile().requests.getState(i).ordinal())); } else { - packet.appendItem(setTag(is, 0, i, true, 0)); + toSend.add(setTag(is, 0, i, true, 0)); } } } - FluidCraft.proxy.netHandler.sendTo(packet, player); + SPacketMEUpdateBuffer.scheduleItemUpdate(player, toSend); } @Nullable diff --git a/src/main/java/com/glodblock/github/network/SPacketMEFluidInvUpdate.java b/src/main/java/com/glodblock/github/network/SPacketMEFluidInvUpdate.java index 0980b805..e72c2ad2 100644 --- a/src/main/java/com/glodblock/github/network/SPacketMEFluidInvUpdate.java +++ b/src/main/java/com/glodblock/github/network/SPacketMEFluidInvUpdate.java @@ -1,7 +1,6 @@ package com.glodblock.github.network; import java.io.IOException; -import java.nio.BufferOverflowException; import java.util.ArrayList; import java.util.List; @@ -13,7 +12,6 @@ import appeng.util.item.AEFluidStack; import com.glodblock.github.client.gui.GuiFluidCraftConfirm; import com.glodblock.github.client.gui.GuiFluidMonitor; -import com.glodblock.github.common.Config; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; @@ -40,8 +38,8 @@ public class SPacketMEFluidInvUpdate implements IMessage { /** * If resort, call "updateView()". Used when multiple packets are sent to open an inventory; only the last packet - * should resort. - * + * should resort + * * @param resort whether this packet should resort the term or not */ public SPacketMEFluidInvUpdate(boolean resort) { @@ -82,12 +80,8 @@ public class SPacketMEFluidInvUpdate implements IMessage { this.resort = resort; } - public void appendFluid(final IAEFluidStack is) throws BufferOverflowException { - if (list.size() <= Config.packetSize) { - list.add(is); - } else { - throw new BufferOverflowException(); - } + public void appendFluid(final IAEFluidStack is) { + list.add(is); } public boolean isEmpty() { diff --git a/src/main/java/com/glodblock/github/network/SPacketMEItemInvUpdate.java b/src/main/java/com/glodblock/github/network/SPacketMEItemInvUpdate.java index 0c48f9dd..b42e0e8f 100644 --- a/src/main/java/com/glodblock/github/network/SPacketMEItemInvUpdate.java +++ b/src/main/java/com/glodblock/github/network/SPacketMEItemInvUpdate.java @@ -1,7 +1,6 @@ package com.glodblock.github.network; import java.io.IOException; -import java.nio.BufferOverflowException; import java.util.ArrayList; import java.util.List; @@ -14,7 +13,6 @@ import appeng.util.item.AEItemStack; import com.glodblock.github.client.gui.GuiFluidCraftConfirm; import com.glodblock.github.client.gui.GuiItemMonitor; import com.glodblock.github.client.gui.GuiLevelMaintainer; -import com.glodblock.github.common.Config; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; @@ -83,12 +81,8 @@ public class SPacketMEItemInvUpdate implements IMessage { this.resort = resort; } - public void appendItem(final IAEItemStack is) throws BufferOverflowException { - if (list.size() <= Config.packetSize) { - list.add(is); - } else { - throw new BufferOverflowException(); - } + public void appendItem(final IAEItemStack is) { + list.add(is); } public boolean isEmpty() { diff --git a/src/main/java/com/glodblock/github/network/SPacketMEUpdateBuffer.java b/src/main/java/com/glodblock/github/network/SPacketMEUpdateBuffer.java new file mode 100644 index 00000000..8b6169bb --- /dev/null +++ b/src/main/java/com/glodblock/github/network/SPacketMEUpdateBuffer.java @@ -0,0 +1,130 @@ +package com.glodblock.github.network; + +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import net.minecraft.entity.player.EntityPlayerMP; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.Config; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent; + +/** + * Only should exist on the server side! Schedules packets to be sent every `packetRate` ms. + */ +public class SPacketMEUpdateBuffer { + + private static ScheduledExecutorService executor; + private static ScheduledFuture task; + + private static final Map> itemBuffer = new HashMap<>(); + + private static final Map> fluidBuffer = new HashMap<>(); + + public static void init() { + executor = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r); + thread.setName("AE2FC Network worker"); + thread.setDaemon(true); + thread.setPriority(6); + return thread; + }); + task = executor + .scheduleAtFixedRate(SPacketMEUpdateBuffer::sendBuffer, 0, Config.packetRate, TimeUnit.MILLISECONDS); + } + + public static void disable() { + task.cancel(false); + executor.shutdown(); + } + + public static void scheduleItemUpdate(EntityPlayerMP player, List stacks) { + synchronized (itemBuffer) { + if (!itemBuffer.containsKey(player)) { + itemBuffer.put(player, new LinkedHashSet<>(1024)); + } + LinkedHashSet buffer = itemBuffer.get(player); + stacks.forEach(s -> buffer.add(s.copy())); + } + } + + public static void scheduleFluidUpdate(EntityPlayerMP player, List stacks) { + synchronized (itemBuffer) { + if (!fluidBuffer.containsKey(player)) { + fluidBuffer.put(player, new LinkedHashSet<>(1024)); + } + LinkedHashSet buffer = fluidBuffer.get(player); + stacks.forEach(s -> buffer.add(s.copy())); + } + } + + public static void sendBuffer() { + synchronized (itemBuffer) { + itemBuffer.forEach((player, updates) -> { + if (updates.isEmpty()) return; + int i = 0; + SPacketMEItemInvUpdate packet = new SPacketMEItemInvUpdate(false); + Iterator it = updates.iterator(); + while (it.hasNext()) { + if (i < Config.packetSize) { + packet.appendItem(it.next()); + it.remove(); + i++; + } else { + FluidCraft.proxy.netHandler.sendTo(packet, player); + packet = new SPacketMEItemInvUpdate(false); + i = 0; + } + } + packet.setResort(true); + FluidCraft.proxy.netHandler.sendTo(packet, player); + }); + fluidBuffer.forEach((player, updates) -> { + if (updates.isEmpty()) return; + int i = 0; + SPacketMEFluidInvUpdate packet = new SPacketMEFluidInvUpdate(false); + Iterator it = updates.iterator(); + while (it.hasNext()) { + if (i < Config.packetSize) { + packet.appendFluid(it.next()); + it.remove(); + i++; + } else { + FluidCraft.proxy.netHandler.sendTo(packet, player); + packet = new SPacketMEFluidInvUpdate(false); + i = 0; + } + } + packet.setResort(true); + FluidCraft.proxy.netHandler.sendTo(packet, player); + }); + + } + } + + public static void clear(EntityPlayerMP player) { + synchronized (itemBuffer) { + if (itemBuffer.containsKey(player)) { + itemBuffer.get(player).clear(); + } + if (fluidBuffer.containsKey(player)) { + fluidBuffer.get(player).clear(); + } + } + } + + @SubscribeEvent + public void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent event) { + if (event.player instanceof EntityPlayerMP) { + clear((EntityPlayerMP) event.player); + } + } +} diff --git a/src/main/java/com/glodblock/github/proxy/CommonProxy.java b/src/main/java/com/glodblock/github/proxy/CommonProxy.java index ac106808..d218aebe 100644 --- a/src/main/java/com/glodblock/github/proxy/CommonProxy.java +++ b/src/main/java/com/glodblock/github/proxy/CommonProxy.java @@ -11,8 +11,10 @@ import com.glodblock.github.common.Config; import com.glodblock.github.common.tile.TileWalrus; import com.glodblock.github.inventory.external.AEFluidInterfaceHandler; import com.glodblock.github.loader.ItemAndBlockHolder; +import com.glodblock.github.network.SPacketMEUpdateBuffer; import com.glodblock.github.util.ModAndClassUtil; +import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @@ -27,6 +29,7 @@ public class CommonProxy { public void init(FMLInitializationEvent event) { this.registerMovables(); + FMLCommonHandler.instance().bus().register(SPacketMEUpdateBuffer.class); } public void postInit(FMLPostInitializationEvent event) {