finished the ram checker and dialog. finished its implementation in neoforge

This commit is contained in:
2025-06-22 02:09:49 +02:00
parent 5dbf6dd823
commit 5e2ff74260
10 changed files with 111 additions and 40 deletions

View File

@@ -4,6 +4,7 @@ import com.vaporvee.loadsupport.platform.Services;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.net.URI;
public class Allocated { public class Allocated {
public static float memoryInGB; public static float memoryInGB;
@@ -17,35 +18,73 @@ public class Allocated {
public static String[] getWarningMessage() { public static String[] getWarningMessage() {
Config config = Services.CONFIG.getConfig(); Config config = Services.CONFIG.getConfig();
return new String[]{config.errorTitle, config.errorDescription
.replace("{minMemory}", String.valueOf(config.minMemory))
.replace("{currentMemory}", String.valueOf(memoryInGB))};
};
static boolean errorWindowOpen = false; String title = stripHtml(config.errorTitle);
String minMemoryText = stripHtml(config.errorMinMemory);
String currentMemoryText = stripHtml(config.errorCurrentMemory);
String minMemoryFormatted = String.format("<span style=\"color:green\">%.1f</span>", config.minMemory);
String currentMemoryFormatted = String.format("<span style=\"color:red\">%.1f</span>", memoryInGB);
String heading = Constants.MOD_NAME + " - " + title;
String body = minMemoryText.replace("{minMemory}", minMemoryFormatted)
+ "<br><br>"
+ currentMemoryText.replace("{currentMemory}", currentMemoryFormatted);
return new String[] { heading, body, config.memoryInfoLink };
}
private static String stripHtml(String input) {
return input == null ? "" : input.replaceAll("<[^>]*>", "");
}
public static boolean enoughMemory = true;
private static JFrame errorWindow; private static JFrame errorWindow;
public static void createErrorWindow() { public static boolean isWindowOpen(){
return errorWindow.isDisplayable();
}
public static void createMemoryError() {
try { try {
if (!errorWindowOpen) { if (enoughMemory) {
errorWindowOpen = true; enoughMemory = false;
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
errorWindow = new JFrame(getWarningMessage()[0]); String[] warning = getWarningMessage();
errorWindow = new JFrame(warning[0]);
errorWindow.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); errorWindow.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
errorWindow.setSize(400, 200); errorWindow.setSize(500, 350);
errorWindow.setLocationRelativeTo(null); errorWindow.setLocationRelativeTo(null);
JLabel message = new JLabel("<html><p style=\"width:200px\">"+ getWarningMessage()[1]+"</p></html>", JLabel.CENTER); JLabel message = new JLabel(
JButton exitButton = new JButton("OK"); "<html><p style=\"width:290px; font-size:16px;\">" + warning[1] + "</p></html>",
JLabel.CENTER
);
exitButton.addActionListener(e -> { JButton okButton = new JButton("OK");
errorWindow.dispose(); okButton.addActionListener(e -> errorWindow.dispose());
//minecraftClient.stop(); // how to get client crossplatform?
int buttonCount = 1 + (!warning[2].isBlank() ? 1 : 0);
JPanel buttonPanel = new JPanel(new GridLayout(1, buttonCount, 10, 0));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
buttonPanel.add(okButton);
if (!warning[2].isBlank()) {
JButton moreInfoButton = new JButton("More info");
moreInfoButton.addActionListener(e -> {
try {
Desktop.getDesktop().browse(new URI(warning[2]));
} catch (Exception ex) {
Constants.LOG.error(String.valueOf(ex));
}
}); });
buttonPanel.add(moreInfoButton);
}
errorWindow.setLayout(new BorderLayout()); errorWindow.setLayout(new BorderLayout());
errorWindow.add(message, BorderLayout.CENTER); errorWindow.add(message, BorderLayout.CENTER);
errorWindow.add(exitButton, BorderLayout.SOUTH); errorWindow.add(buttonPanel, BorderLayout.SOUTH);
errorWindow.setVisible(true); errorWindow.setVisible(true);
}); });
} }

View File

@@ -20,7 +20,7 @@ public class CommonClass {
System.setProperty("java.awt.headless", "false"); System.setProperty("java.awt.headless", "false");
Constants.LOG.error("Not enough memory! Allocated memory in GB is {} but set in config is {}", Constants.LOG.error("Not enough memory! Allocated memory in GB is {} but set in config is {}",
Allocated.memoryInGB, config.minMemory); Allocated.memoryInGB, config.minMemory);
Allocated.createErrorWindow(); Allocated.createMemoryError();
} }
} else { } else {
Constants.LOG.warn("Load config is null!"); Constants.LOG.warn("Load config is null!");

View File

@@ -7,5 +7,7 @@ public class Config implements ConfigData {
boolean startSound = true; boolean startSound = true;
float minMemory = 4.0f; float minMemory = 4.0f;
String errorTitle = "Error: Not enough Java memory!"; String errorTitle = "Error: Not enough Java memory!";
String errorDescription = "Please allocate at least {minMemory} GB of Java memory to your Minecraft Instance! You have currently {currentMemory} GB allocated."; String errorMinMemory = "Please allocate at least {minMemory} GB of Java memory to your Minecraft instance!";
String errorCurrentMemory = "You have currently {currentMemory} GB allocated.";
String memoryInfoLink = "https://github.com/vaporvee/LoadSupport/wiki/How-to-allocate-more-memory-to-your-Minecraft-instance";
} }

View File

@@ -2,6 +2,7 @@ package com.vaporvee.loadsupport;
import com.vaporvee.loadsupport.platform.Services; import com.vaporvee.loadsupport.platform.Services;
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.Mod; import net.neoforged.fml.common.Mod;

View File

@@ -0,0 +1,21 @@
package com.vaporvee.loadsupport.mixin;
import com.vaporvee.loadsupport.Allocated;
import net.minecraft.client.Minecraft;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MinecraftPauseMixin {
@Inject(method = "run", at = @At("HEAD"), cancellable = true)
private void onRunHead(CallbackInfo ci) {
if (!Allocated.enoughMemory) {
while (Allocated.isWindowOpen()) {
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
}
ci.cancel();
}
}
}

View File

@@ -1,18 +0,0 @@
package com.vaporvee.loadsupport.mixin;
import com.vaporvee.loadsupport.Constants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public class MixinTitleScreen {
@Inject(at = @At("HEAD"), method = "init()V")
private void init(CallbackInfo info) {
Constants.LOG.info("Mixin MC title Type: {}", Minecraft.getInstance().getVersionType());
}
}

View File

@@ -0,0 +1,23 @@
package com.vaporvee.loadsupport.mixin;
import com.mojang.blaze3d.platform.Window;
import com.vaporvee.loadsupport.Allocated;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Window.class)
public class WindowHideMixin {
@Inject(
method = "takeOverWindow",
at = @At("RETURN")
)
private void onTakeOverWindow(CallbackInfoReturnable<Long> cir) {
if (!Allocated.enoughMemory) {
long w = cir.getReturnValue();
GLFW.glfwHideWindow(w);
}
}
}

View File

@@ -5,6 +5,7 @@ import com.vaporvee.loadsupport.Config;
import com.vaporvee.loadsupport.platform.services.IConfig; import com.vaporvee.loadsupport.platform.services.IConfig;
import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer; import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer;
import net.neoforged.neoforge.client.event.ScreenEvent;
public class LSConfigNeoForge implements IConfig { public class LSConfigNeoForge implements IConfig {
public static Config config; public static Config config;
@@ -13,6 +14,7 @@ public class LSConfigNeoForge implements IConfig {
AutoConfig.register(Config.class, Toml4jConfigSerializer::new); AutoConfig.register(Config.class, Toml4jConfigSerializer::new);
config = AutoConfig.getConfigHolder(Config.class).getConfig(); config = AutoConfig.getConfigHolder(Config.class).getConfig();
CommonClass.checkConfig(config); CommonClass.checkConfig(config);
} }
@Override @Override
public Config getConfig() { public Config getConfig() {

View File

@@ -5,7 +5,8 @@
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [], "mixins": [],
"client": [ "client": [
"MixinTitleScreen" "MinecraftPauseMixin",
"WindowHideMixin"
], ],
"server": [], "server": [],
"injectors": { "injectors": {