Various CPU and RAM improvements (#1015)

Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
boubou19andMartin Robertz authored and GitHub committed 2026-09-03 00:07:25 +03:00
1 parent 866b796411
commit 3f38e6f39b
9 files changed
+236 -54

No files matched your search

+21 -8
View File
@@ -19,6 +19,7 @@ import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
@@ -348,16 +349,24 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
public void setGridSize(int mleft, int mtop, int w, int h) {
final int newWidth = Math.max(0, w);
final int newHeight = Math.max(0, h);
final boolean changed = marginLeft != mleft || marginTop != mtop || width != newWidth || height != newHeight;
marginLeft = mleft;
marginTop = mtop;
width = Math.max(0, w);
height = Math.max(0, h);
width = newWidth;
height = newHeight;
columns = width / SLOT_SIZE;
rows = height / SLOT_SIZE;
paddingLeft = (width % SLOT_SIZE) / 2;
if (changed) {
onGridChanged();
}
}
public void shiftPage(int shift) {
@@ -396,7 +405,10 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
public void refresh(GuiContainer gui) {
updateGuiOverlapSlots(gui);
final int gridRenderingCacheMode = getGridRenderingCacheMode();
if (gridRenderingCacheMode <= 0 || screenCapture == null || screenCapture.needRefresh(gridRenderingCacheMode)) {
updateGuiOverlapSlots(gui);
}
shiftPage(0);
}
@@ -409,11 +421,12 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
perPage = columns * rows;
if (gui != null) {
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
checkGuiOverlap(gui, handlers, 0, columns - 2, 1);
checkGuiOverlap(gui, handlers, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
checkGuiOverlap(gui, handlers, 0, columns, 1);
}
}
@@ -422,7 +435,7 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
}
private void checkGuiOverlap(GuiContainer gui, int start, int end, int dir) {
private void checkGuiOverlap(GuiContainer gui, INEIGuiHandler[] handlers, int start, int end, int dir) {
boolean validColumn = false;
for (int c = start; c != end && (!NEIClientConfig.optimizeGuiOverlapComputation() || !validColumn); c += dir) {
@@ -432,7 +445,7 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
final int idx = columns * r + c;
if (idx >= 0 && idx < invalidSlotMap.length
&& !invalidSlotMap[idx]
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c))) {
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c), handlers)) {
invalidSlotMap[idx] = true;
validColumn = false;
perPage--;
@@ -43,6 +43,7 @@ import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.gui.inventory.GuiContainerCreative;
import net.minecraft.client.renderer.InventoryEffectRenderer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -907,21 +908,37 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
GL11.glEnable(GL11.GL_TEXTURE_2D);
changeTexture("textures/gui/widgets.png");
drawTexturedModalRect(x, y, tx1, ty1, w1, h1); // top left
drawTexturedModalRect(x, y2, tx1, ty2, w1, h2); // bottom left
final Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
addTexturedModalRect(tessellator, x, y, tx1, ty1, w1, h1); // top left
addTexturedModalRect(tessellator, x, y2, tx1, ty2, w1, h2); // bottom left
for (int tile = 0; tile < wTiles; tile++) {
final int tileX = x + w1 + 50 * tile;
drawTexturedModalRect(tileX, y, tx3, ty1, 50, h1); // top
drawTexturedModalRect(tileX, y2, tx3, ty2, 50, h2); // bottom
addTexturedModalRect(tessellator, tileX, y, tx3, ty1, 50, h1); // top
addTexturedModalRect(tessellator, tileX, y2, tx3, ty2, 50, h2); // bottom
}
drawTexturedModalRect(x2, y, tx2, ty1, w2, h1); // top right
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
addTexturedModalRect(tessellator, x2, y, tx2, ty1, w2, h1); // top right
addTexturedModalRect(tessellator, x2, y2, tx2, ty2, w2, h2); // bottom right
tessellator.draw();
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
}
private static void addTexturedModalRect(Tessellator tessellator, int x, int y, int textureX, int textureY,
int width, int height) {
final double z = GuiDraw.gui.getZLevel();
final double u = textureX / 256D;
final double v = textureY / 256D;
final double maxU = (textureX + width) / 256D;
final double maxV = (textureY + height) / 256D;
tessellator.addVertexWithUV(x, y + height, z, u, maxV);
tessellator.addVertexWithUV(x + width, y + height, z, maxU, maxV);
tessellator.addVertexWithUV(x + width, y, z, maxU, v);
tessellator.addVertexWithUV(x, y, z, u, v);
}
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
if (slotHighlight) {
@@ -1,14 +1,10 @@
package codechicken.nei;
import java.util.Collection;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.InventoryEffectRenderer;
import net.minecraft.potion.PotionEffect;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.INEIGuiAdapter;
/**
@@ -18,35 +14,37 @@ public class NEIPotionGuiHandler extends INEIGuiAdapter {
@Override
public boolean hideItemPanelSlot(GuiContainer guiContainer, int slotX, int slotY, int slotW, int slotH) {
if (NEIClientConfig.ignorePotionOverlap()) {
if (!(guiContainer instanceof InventoryEffectRenderer)) {
return false;
}
if (guiContainer instanceof InventoryEffectRenderer) {
int x = guiContainer.guiLeft - 124;
int y = guiContainer.guiTop;
Minecraft minecraft = guiContainer.mc;
if (minecraft == null) {
return false;
}
EntityPlayerSP player = minecraft.thePlayer;
if (player == null) {
return false;
}
Collection<PotionEffect> activePotionEffects = player.getActivePotionEffects();
if (activePotionEffects.isEmpty()) {
return false;
}
int height = 33;
if (activePotionEffects.size() > 5) {
height = 132 / (activePotionEffects.size() - 1);
}
Rectangle4i slotRect = new Rectangle4i(slotX, slotY, slotW, slotH);
for (PotionEffect potioneffect : activePotionEffects) {
Rectangle4i box = new Rectangle4i(x, y, 140, 32);
if (box.intersects(slotRect)) return true;
y += height;
}
int x = guiContainer.guiLeft - 124;
if (slotX + slotW <= x || slotX >= x + 140) {
return false;
}
Minecraft minecraft = guiContainer.mc;
if (minecraft == null) {
return false;
}
EntityPlayerSP player = minecraft.thePlayer;
if (player == null) {
return false;
}
int potionCount = player.getActivePotionEffects().size();
if (potionCount == 0 || NEIClientConfig.ignorePotionOverlap()) {
return false;
}
int height = 33;
if (potionCount > 5) {
height = 132 / (potionCount - 1);
}
return intersectsPotionEffects(slotY, slotH, guiContainer.guiTop, potionCount, height);
}
static boolean intersectsPotionEffects(int slotY, int slotH, int effectY, int potionCount, int height) {
for (int i = 0; i < potionCount; i++, effectY += height) {
if (slotY + slotH > effectY && slotY < effectY + 32) return true;
}
return false;
}
+14 -5
View File
@@ -51,20 +51,29 @@ public class GuiInfo {
}
public static boolean hideItemPanelSlot(GuiContainer gui, Rectangle4i rect) {
return hideItemPanelSlot(gui, rect, getGuiHandlersSnapshot());
}
public static INEIGuiHandler[] getGuiHandlersSnapshot() {
try {
readLock.lock();
if (guiHandlers.stream()
.anyMatch(handler -> handler.hideItemPanelSlot(gui, rect.x, rect.y, rect.w, rect.h))) {
return true;
}
return guiHandlers.toArray(new INEIGuiHandler[0]);
} finally {
readLock.unlock();
}
}
public static boolean hideItemPanelSlot(GuiContainer gui, Rectangle4i rect, INEIGuiHandler[] handlers) {
for (INEIGuiHandler handler : handlers) {
if (handler.hideItemPanelSlot(gui, rect.x, rect.y, rect.w, rect.h)) return true;
}
for (Object item : gui.buttonList) {
GuiButton button = (GuiButton) item;
if ((new Rectangle4i(button.xPosition, button.yPosition, button.width, button.height)).intersects(rect)) {
if (button.xPosition + button.width > rect.x && button.xPosition < rect.x + rect.w
&& button.yPosition + button.height > rect.y
&& button.yPosition < rect.y + rect.h) {
return true;
}
}
@@ -314,7 +314,7 @@ public class GuiContainerManager {
}
private static int modelviewDepth = -1;
private static boolean contextEnabled = false;
private static int contextDepth = 0;
private static final ItemStackSet renderingErrorItems = new ItemStackSet();
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, FontRenderer fontRenderer,
@@ -411,16 +411,15 @@ public class GuiContainerManager {
}
public static void enableMatrixStackLogging() {
if (!contextEnabled) {
if (contextDepth == 0) {
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
modelviewDepth = GL11.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH);
contextEnabled = true;
}
contextDepth++;
}
public static void disableMatrixStackLogging() {
if (contextEnabled) {
contextEnabled = false;
if (contextDepth > 0 && --contextDepth == 0) {
modelviewDepth = -1;
GL11.glPopAttrib();
}
@@ -0,0 +1,58 @@
package codechicken.nei;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.junit.jupiter.api.Test;
public class ItemsGridTest {
@Test
void synchronizesOverlapAndCaptureRefresh() {
TestGrid grid = new TestGrid();
ItemsGrid.ScreenCapture capture = mock(ItemsGrid.ScreenCapture.class);
grid.screenCapture = capture;
grid.setGridSize(1, 2, 18, 18);
grid.setGridSize(1, 2, 18, 18);
verify(capture, times(1)).refreshBuffer();
when(capture.needRefresh(1)).thenReturn(false, true);
grid.refresh(null);
grid.refresh(null);
assertEquals(1, grid.overlapRefreshes);
}
private static final class TestGrid extends ItemsGrid<ItemsGrid.ItemsGridSlot, ItemsGrid.MouseContext> {
private int overlapRefreshes;
@Override
protected int getGridRenderingCacheMode() {
return 1;
}
@Override
protected void updateGuiOverlapSlots(GuiContainer gui) {
overlapRefreshes++;
}
@Override
public List<ItemsGrid.ItemsGridSlot> getMask() {
return Collections.emptyList();
}
@Override
protected ItemsGrid.MouseContext getMouseContext(int mousex, int mousey) {
return null;
}
}
}
@@ -0,0 +1,26 @@
package codechicken.nei;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import net.minecraft.client.renderer.InventoryEffectRenderer;
import org.junit.jupiter.api.Test;
public class NEIPotionGuiHandlerTest {
@Test
void preservesGapsBetweenPotionBoxes() {
assertTrue(NEIPotionGuiHandler.intersectsPotionEffects(131, 1, 100, 2, 33));
assertFalse(NEIPotionGuiHandler.intersectsPotionEffects(132, 1, 100, 2, 33));
}
@Test
void skipsConfigLookupOutsidePotionColumn() {
InventoryEffectRenderer gui = mock(InventoryEffectRenderer.class);
gui.guiLeft = 200;
assertFalse(new NEIPotionGuiHandler().hideItemPanelSlot(gui, 216, 100, 1, 1));
}
}
@@ -0,0 +1,36 @@
package codechicken.nei.api;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.junit.jupiter.api.Test;
import codechicken.lib.vec.Rectangle4i;
public class GuiInfoTest {
@Test
void checksProvidedHandlerSnapshot() {
GuiContainer gui = mock(GuiContainer.class);
INEIGuiHandler handler = mock(INEIGuiHandler.class);
when(handler.hideItemPanelSlot(gui, 1, 2, 3, 4)).thenReturn(true);
assertTrue(GuiInfo.hideItemPanelSlot(gui, new Rectangle4i(1, 2, 3, 4), new INEIGuiHandler[] { handler }));
}
@Test
void buttonEdgeContactDoesNotOverlap() {
GuiContainer gui = mock(GuiContainer.class);
gui.buttonList = Collections.singletonList(new GuiButton(0, 10, 10, 10, 10, ""));
assertTrue(GuiInfo.hideItemPanelSlot(gui, new Rectangle4i(19, 19, 1, 1), new INEIGuiHandler[0]));
assertFalse(GuiInfo.hideItemPanelSlot(gui, new Rectangle4i(20, 10, 1, 1), new INEIGuiHandler[0]));
}
}
@@ -0,0 +1,26 @@
package codechicken.nei.guihook;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import org.junit.jupiter.api.Test;
import org.lwjgl.opengl.GL11;
import org.mockito.MockedStatic;
public class GuiContainerManagerTest {
@Test
void matrixStackLoggingSupportsNestedContexts() {
try (MockedStatic<GL11> gl = mockStatic(GL11.class)) {
GuiContainerManager.enableMatrixStackLogging();
GuiContainerManager.enableMatrixStackLogging();
GuiContainerManager.disableMatrixStackLogging();
gl.verify(() -> GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT));
gl.verify(GL11::glPopAttrib, times(0));
GuiContainerManager.disableMatrixStackLogging();
gl.verify(GL11::glPopAttrib);
}
}
}