Optimisations

This commit is contained in:
2025-09-03 02:51:19 +02:00
parent ca9626f340
commit 8089deb172
9 changed files with 375 additions and 380 deletions
@@ -1,11 +1,14 @@
package org.saturnclient.modules; package org.saturnclient.modules;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import java.util.ArrayList;
import java.util.List;
import org.saturnclient.modules.mods.*; import org.saturnclient.modules.mods.*;
public class ModManager { public class ModManager {
public static Module[] MODS = { public static final List<Module> ENABLED_MODS = new ArrayList<>();
public static final Module[] ALL_MODS = {
new Crosshair(), new Crosshair(),
new AutoSprint(), new AutoSprint(),
new ArmorDisplay(), new ArmorDisplay(),
@@ -17,12 +20,31 @@ public class ModManager {
}; };
public static void init() { public static void init() {
// Pre-filter enabled modules to avoid checking every tick
updateEnabledModules();
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
for (Module m : MODS) { // Only iterate over enabled modules
if (m.isEnabled()) { for (Module m : ENABLED_MODS) {
m.tick(); m.tick();
}
} }
}); });
} }
public static void updateEnabledModules() {
ENABLED_MODS.clear();
for (Module m : ALL_MODS) {
if (m.isEnabled()) {
ENABLED_MODS.add(m);
}
}
}
public static Module[] getAllMods() {
return ALL_MODS;
}
public static void refreshEnabledModules() {
updateEnabledModules();
}
} }
@@ -13,6 +13,8 @@ public class Keystrokes extends Module implements HudMod {
public static Property<Boolean> showMouse = Property.bool(true); public static Property<Boolean> showMouse = Property.bool(true);
public static Property<Boolean> showSpace = Property.bool(false); public static Property<Boolean> showSpace = Property.bool(false);
public static ModDimensions dimensions = new ModDimensions(78, 46); public static ModDimensions dimensions = new ModDimensions(78, 46);
// Cache key states to avoid repeated calls
private boolean w = false; private boolean w = false;
private boolean a = false; private boolean a = false;
private boolean s = false; private boolean s = false;
@@ -21,27 +23,32 @@ public class Keystrokes extends Module implements HudMod {
private boolean rmb = false; private boolean rmb = false;
private boolean space = false; private boolean space = false;
// Cache dimensions to avoid recalculation
private int cachedHeight = 54;
private boolean dimensionsDirty = true;
private static Property<Integer> clickBg = Property.color(0xFFCCCCCC); private static Property<Integer> clickBg = Property.color(0xFFCCCCCC);
private static Property<Integer> clickFg = Property.color(0xFFFFFFFF); private static Property<Integer> clickFg = Property.color(0xFFFFFFFF);
public Keystrokes() { public Keystrokes() {
super(new ModuleDetails("Keystrokes", "keystrokes") super(new ModuleDetails("Keystrokes", "keystrokes")
.description("Displays the keystrokes for movement") .description("Displays the keystrokes for movement")
.version("v0.1.0") .version("v0.1.0")
.tags("Utility"), .tags("Utility"),
enabled.named("Enabled"), enabled.named("Enabled"),
showMouse.named("Show mouse clicks"), showMouse.named("Show mouse clicks"),
showSpace.named("Show space clicks"), showSpace.named("Show space clicks"),
dimensions.prop(), dimensions.prop(),
clickFg.named("Clicked fg"), clickFg.named("Clicked fg"),
clickBg.named("Clicked bg")); clickBg.named("Clicked bg"));
dimensions.renderBackground = false; dimensions.renderBackground = false;
} }
@Override @Override
public void tick() { public void tick() {
// Cache key states to reduce method calls
w = SaturnClient.client.options.forwardKey.isPressed(); w = SaturnClient.client.options.forwardKey.isPressed();
a = SaturnClient.client.options.leftKey.isPressed(); a = SaturnClient.client.options.leftKey.isPressed();
s = SaturnClient.client.options.backKey.isPressed(); s = SaturnClient.client.options.backKey.isPressed();
@@ -49,49 +56,67 @@ public class Keystrokes extends Module implements HudMod {
lmb = SaturnClient.client.options.attackKey.isPressed(); lmb = SaturnClient.client.options.attackKey.isPressed();
rmb = SaturnClient.client.options.useKey.isPressed(); rmb = SaturnClient.client.options.useKey.isPressed();
space = SaturnClient.client.options.jumpKey.isPressed(); space = SaturnClient.client.options.jumpKey.isPressed();
// Mark dimensions as dirty if mouse or space visibility changed
if (dimensionsDirty) {
updateDimensions();
dimensionsDirty = false;
}
}
private void updateDimensions() {
cachedHeight = 54; // base height with padding considered
if (showMouse.value) {
cachedHeight += 27;
}
if (showSpace.value) {
cachedHeight += 22;
}
dimensions.height = cachedHeight;
} }
@Override @Override
public void renderDummy(RenderScope scope) { public void renderDummy(RenderScope scope) {
dimensions.height = 54; // base height with padding considered // Use cached dimensions
dimensions.height = cachedHeight;
// WASD keys (3px padding between each key) // WASD keys (3px padding between each key)
renderKey(scope, true, 'W', 27, 0); // Top center renderKey(scope, false, 'W', 27, 0); // Top center
renderKey(scope, false, 'A', 0, 27); // Bottom left renderKey(scope, false, 'A', 0, 27); // Bottom left
renderKey(scope, false, 'S', 27, 27); // Bottom center renderKey(scope, false, 'S', 27, 27); // Bottom center
renderKey(scope, false, 'D', 54, 27); // Bottom right renderKey(scope, false, 'D', 54, 27); // Bottom right
if (showMouse.value) { if (showMouse.value) {
renderKeyM(scope, true, "LMB", 0, 54); // Below A/S/D renderKeyM(scope, false, "LMB", 0, 54); // Below A/S/D
renderKeyM(scope, false, "RMB", 40, 54); // With 3px between renderKeyM(scope, false, "RMB", 40, 54); // With 3px between
dimensions.height += 27;
} }
if (showSpace.value) { if (showSpace.value) {
renderKeySpace(scope, false, 0, dimensions.height); renderKeySpace(scope, false, 0, cachedHeight - (showSpace.value ? 22 : 0));
dimensions.height += 22;
} }
} }
@Override @Override
public void renderHud(RenderScope scope) { public void renderHud(RenderScope scope) {
dimensions.height = 54; // base height with padding considered // Use cached dimensions
dimensions.height = cachedHeight;
// WASD keys (3px padding between each key) // WASD keys (3px padding between each key)
renderKey(scope, w, 'W', 27, 0); // Top center renderKey(scope, w, 'W', 27, 0); // Top center
renderKey(scope, a, 'A', 0, 27); // Bottom left renderKey(scope, a, 'A', 0, 27); // Bottom left
renderKey(scope, s, 'S', 27, 27); // Bottom center renderKey(scope, s, 'S', 27, 27); // Bottom center
renderKey(scope, d, 'D', 54, 27); // Bottom right renderKey(scope, d, 'D', 54, 27); // Bottom right
if (showMouse.value) { if (showMouse.value) {
renderKeyM(scope, lmb, "LMB", 0, 54); // Below A/S/D renderKeyM(scope, lmb, "LMB", 0, 54); // Below A/S/D
renderKeyM(scope, rmb, "RMB", 40, 54); // With 3px between renderKeyM(scope, rmb, "RMB", 40, 54); // With 3px between
dimensions.height += 27;
} }
if (showSpace.value) { if (showSpace.value) {
renderKeySpace(scope, space, 0, dimensions.height); renderKeySpace(scope, space, 0, cachedHeight - (showSpace.value ? 22 : 0));
dimensions.height += 22;
} }
} }
@@ -99,29 +124,38 @@ public class Keystrokes extends Module implements HudMod {
private void renderKeySpace(RenderScope scope, boolean isPressed, int x, int y) { private void renderKeySpace(RenderScope scope, boolean isPressed, int x, int y) {
int height = 19; int height = 19;
scope.drawRoundedRectangle(x, y, dimensions.width, height, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value); int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
scope.drawRoundedRectangle(x, y, dimensions.width, height, dimensions.radius.value, bgColor);
// A 30-pixel line centered vertically with 3px top padding // A 30-pixel line centered vertically with 3px top padding
int lineY = y + (height - 1) / 2; int lineY = y + (height - 1) / 2;
scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, isPressed ? clickFg.value : dimensions.fgColor.value); scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, fgColor);
} }
private void renderKeyM(RenderScope scope, boolean isPressed, String c, int x, int y) { private void renderKeyM(RenderScope scope, boolean isPressed, String c, int x, int y) {
int width = 38, height = 24; int width = 38, height = 24;
scope.drawRoundedRectangle(x, y, width, height, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value); int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
scope.drawRoundedRectangle(x, y, width, height, dimensions.radius.value, bgColor);
// Apply padding: 3px top and left -> add slight offset to x/y // Apply padding: 3px top and left -> add slight offset to x/y
scope.drawText(0.6f, c, x + 9, y + 7, dimensions.font.value, isPressed ? clickFg.value : dimensions.fgColor.value); scope.drawText(0.6f, c, x + 9, y + 7, dimensions.font.value, fgColor);
} }
private void renderKey(RenderScope scope, boolean isPressed, char c, int x, int y) { private void renderKey(RenderScope scope, boolean isPressed, char c, int x, int y) {
int size = 24; int size = 24;
scope.drawRoundedRectangle(x, y, size, size, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value); int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
scope.drawRoundedRectangle(x, y, size, size, dimensions.radius.value, bgColor);
// Center the character with 3px top padding // Center the character with 3px top padding
scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, isPressed ? clickFg.value : dimensions.fgColor.value); scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, fgColor);
} }
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return enabled.value; return enabled.value;
@@ -135,5 +169,6 @@ public class Keystrokes extends Module implements HudMod {
@Override @Override
public void setEnabled(boolean e) { public void setEnabled(boolean e) {
enabled.value = e; enabled.value = e;
dimensionsDirty = true;
} }
} }
@@ -29,7 +29,7 @@ public class RenderMixin {
RenderScope renderScope = new RenderScope(context.getMatrices(), RenderScope renderScope = new RenderScope(context.getMatrices(),
((DrawContextAccessor) context).getVertexConsumers()); ((DrawContextAccessor) context).getVertexConsumers());
for (org.saturnclient.modules.Module m : ModManager.MODS) { for (org.saturnclient.modules.Module m : ModManager.ENABLED_MODS) {
if (m instanceof HudMod && m.isEnabled()) { if (m instanceof HudMod && m.isEnabled()) {
ModDimensions dim = ((HudMod) m).getDimensions(); ModDimensions dim = ((HudMod) m).getDimensions();
@@ -28,7 +28,6 @@ public class Auth {
private static Thread pingThread; private static Thread pingThread;
private static volatile boolean running = false; private static volatile boolean running = false;
@SuppressWarnings("resource")
public static boolean authenticate() { public static boolean authenticate() {
// Register shutdown hook ONCE // Register shutdown hook ONCE
ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> close()); ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> close());
@@ -1,223 +1,116 @@
package org.saturnclient.saturnclient.config; package org.saturnclient.saturnclient.config;
import com.google.gson.Gson; import com.google.gson.*;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.HashMap; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
public class ConfigManager { public class ConfigManager {
private static File configFile = new File( private static final File configFile = new File(SaturnClient.client.runDirectory, "saturn.json");
SaturnClient.client.runDirectory, private static final Map<String, Map<String, Property<?>>> properties = new HashMap<>();
"saturn.json");
private static Map<String, Map<String, Property<?>>> properties = new HashMap<>();
private static JsonObject cachedThemeJson = null; private static JsonObject cachedThemeJson = null;
private Map<String, Property<?>> currentMap; private final Map<String, Property<?>> currentMap;
private String namespace; private final String namespace;
public ConfigManager(String namespace) { public ConfigManager(String namespace) {
currentMap = new LinkedHashMap<>(); this.namespace = namespace;
this.currentMap = new LinkedHashMap<>();
properties.put(namespace, currentMap); properties.put(namespace, currentMap);
System.out.println("Created namespace: " + namespace); System.out.println("Created namespace: " + namespace);
} }
public ConfigManager(ConfigManager config, String namespace) { public ConfigManager(ConfigManager parent, String namespace) {
currentMap = new LinkedHashMap<>(); this.namespace = namespace;
Property<Map<String, Property<?>>> namespaceProperty = Property.namespace(currentMap); this.currentMap = new LinkedHashMap<>();
config.property(namespace, namespaceProperty); Property<Map<String, Property<?>>> nsProp = Property.namespace(currentMap);
// Update the parent's state parent.property(namespace, nsProp);
config.currentMap.put(namespace, namespaceProperty);
System.out.println("Created sub-namespace: " + namespace); System.out.println("Created sub-namespace: " + namespace);
} }
public void sub(String namespace) { public void sub(String name) {
Property<Map<String, Property<?>>> namespaceProperty = Property.namespace(currentMap); property(name, Property.namespace(new LinkedHashMap<>()));
property(namespace, namespaceProperty);
} }
// Generic method to store any type of property
public <T> Property<T> property(String name, Property<T> value) { public <T> Property<T> property(String name, Property<T> value) {
currentMap.put(name, value); currentMap.put(name, value);
loadProp(name, value); loadProp(name, value);
return value; return value;
} }
@SuppressWarnings("unchecked") private <T> void loadProp(String name, Property<T> prop) {
public <T> void loadProp(String name, Property<T> prop) { JsonObject source = cachedThemeJson != null ? cachedThemeJson : loadAndCache();
if (cachedThemeJson != null) { if (source == null)
JsonElement element = cachedThemeJson.get(namespace); return;
if (element != null && element.isJsonObject()) {
JsonObject theme = element.getAsJsonObject(); JsonElement namespaceJson = source.get(namespace);
JsonElement value = theme.get(name); if (namespaceJson == null || !namespaceJson.isJsonObject())
if (value != null && prop.matchesJson(value)) { return;
switch (prop.getType()) {
case BOOLEAN: JsonElement value = namespaceJson.getAsJsonObject().get(name);
((Property<Boolean>) prop).setValue(value.getAsBoolean()); if (value != null)
break; prop.loadFromJson(value);
case INTEGER: }
((Property<Integer>) prop).setValue(value.getAsInt());
break; private static JsonObject loadAndCache() {
case FLOAT: try {
((Property<Float>) prop).setValue(value.getAsFloat()); if (!configFile.exists()) {
break; Files.writeString(configFile.toPath(), "{}");
case STRING: return new JsonObject();
((Property<String>) prop).setValue(value.getAsString());
break;
case HEX:
((Property<Integer>) prop).setValue(value.getAsInt());
break;
default:
break;
}
}
} }
} else { String json = Files.readString(configFile.toPath());
load(); cachedThemeJson = JsonParser.parseString(json).getAsJsonObject();
return cachedThemeJson;
} catch (IOException e) {
SaturnClient.LOGGER.error("Error reading config file", e);
return null;
} }
} }
public static void load() { public static void load() {
try { SaturnClient.LOGGER.info("Loading config...");
SaturnClient.LOGGER.info("Starting to load config..."); JsonObject json = loadAndCache();
if (!configFile.exists()) { if (json == null)
configFile.createNewFile(); return;
Files.write(configFile.toPath(), "{}".getBytes());
properties.forEach((namespace, map) -> {
JsonElement nsElement = json.get(namespace);
if (nsElement != null && nsElement.isJsonObject()) {
loadProperties(nsElement.getAsJsonObject(), map);
} }
});
JsonObject jsonObject = JsonParser.parseString(
new String(Files.readAllBytes(configFile.toPath()))).getAsJsonObject();
for (String namespace : properties.keySet()) {
JsonElement configElement = jsonObject.get(namespace);
if (configElement == null)
continue;
JsonObject config = jsonObject.get(namespace).getAsJsonObject();
if (config == null) {
continue;
}
Map<String, Property<?>> propertyMap = properties.get(namespace);
loadProperties(config, propertyMap);
}
} catch (IOException e) {
SaturnClient.LOGGER.error("Error reading the config file", e);
}
} }
@SuppressWarnings("unchecked") private static void loadProperties(JsonObject json, Map<String, Property<?>> props) {
private static void loadProperties(JsonObject config, Map<String, Property<?>> propertyMap) { props.forEach((name, prop) -> {
for (String propertyName : propertyMap.keySet()) { JsonElement el = json.get(name);
JsonElement c = config.get(propertyName); if (el != null)
prop.loadFromJson(el);
if (c == null) { });
continue;
}
Property<?> p = propertyMap.get(propertyName);
if (p.matchesJson(c)) {
if (p.getType() == Property.PropertyType.NAMESPACE) {
// Handle nested namespace
JsonObject nestedConfig = c.getAsJsonObject();
Map<String, Property<?>> nestedProperties = p.getNamespaceValue();
loadProperties(nestedConfig, nestedProperties);
} else {
if (p.value instanceof Integer) {
((Property<Integer>) p).value = c.getAsInt();
} else if (p.value instanceof String) {
((Property<String>) p).value = c.getAsString();
} else if (p.value instanceof Float) {
((Property<Float>) p).value = c.getAsFloat();
} else if (p.value instanceof Boolean) {
((Property<Boolean>) p).value = c.getAsBoolean();
} else {
SaturnClient.LOGGER.warn(
"Unknown property type for: " + propertyName);
}
}
} else {
SaturnClient.LOGGER.warn(
"Property does not match JSON: " + propertyName);
}
}
} }
public static void save() { public static void save() {
SaturnClient.LOGGER.info("Saving config...");
JsonObject root = new JsonObject();
properties.forEach((namespace, map) -> {
JsonObject nsJson = new JsonObject();
saveProperties(nsJson, map);
root.add(namespace, nsJson);
});
try { try {
SaturnClient.LOGGER.info("Starting to save config..."); String formatted = new GsonBuilder().setPrettyPrinting().create().toJson(root);
Files.writeString(configFile.toPath(), formatted);
JsonObject jsonObject = new JsonObject();
// Iterate through all namespaces and their properties
for (String namespace : properties.keySet()) {
JsonObject namespaceConfig = new JsonObject();
Map<String, Property<?>> propertyMap = properties.get(namespace);
// Save properties for this namespace
saveProperties(namespaceConfig, propertyMap);
// Add the namespace config to the main JSON object
jsonObject.add(namespace, namespaceConfig);
}
// Format the json so it can easily be edited
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String formattedJson = gson.toJson(jsonObject);
// Write the JSON object to the config file
Files.write(configFile.toPath(), formattedJson.getBytes());
SaturnClient.LOGGER.info("Config saved successfully."); SaturnClient.LOGGER.info("Config saved successfully.");
} catch (IOException e) { } catch (IOException e) {
SaturnClient.LOGGER.error("Error saving the config file", e); SaturnClient.LOGGER.error("Error saving config file", e);
} }
} }
@SuppressWarnings("unchecked") private static void saveProperties(JsonObject json, Map<String, Property<?>> props) {
private static void saveProperties(JsonObject config, Map<String, Property<?>> propertyMap) { props.forEach((name, prop) -> json.add(name, prop.toJson()));
// Iterate through each property in the namespace
for (String propertyName : propertyMap.keySet()) {
Property<?> property = propertyMap.get(propertyName);
JsonElement propertyValue = null;
// Convert the property value based on its type
switch (property.getType()) {
case NAMESPACE:
// Handle nested namespace
JsonObject nestedConfig = new JsonObject();
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) property.value;
saveProperties(nestedConfig, nestedProperties);
propertyValue = nestedConfig;
break;
default:
if (property.value instanceof Integer) {
propertyValue = new JsonPrimitive((Integer) property.value);
} else if (property.value instanceof String) {
propertyValue = new JsonPrimitive((String) property.value);
} else if (property.value instanceof Float) {
propertyValue = new JsonPrimitive((Float) property.value);
} else if (property.value instanceof Boolean) {
propertyValue = new JsonPrimitive((Boolean) property.value);
} else {
SaturnClient.LOGGER.warn(
"Unknown property type for: " + propertyName);
}
break;
}
if (propertyValue != null) {
config.add(propertyName, propertyValue);
}
}
} }
public Map<String, Property<?>> getProperties() { public Map<String, Property<?>> getProperties() {
@@ -6,6 +6,7 @@ import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
public class Property<T> { public class Property<T> {
@@ -25,7 +26,7 @@ public class Property<T> {
public boolean isReset = false; public boolean isReset = false;
private T defaultValue; private T defaultValue;
private String[] availableValues; private String[] availableValues;
private PropertyType type; private final PropertyType type;
private boolean wasPressedLastTick = false; private boolean wasPressedLastTick = false;
private Property(T value, PropertyType type) { private Property(T value, PropertyType type) {
@@ -34,24 +35,19 @@ public class Property<T> {
this.type = type; this.type = type;
} }
// ---------- Factory Methods ----------
public static <T> Property<T> from(T value) { public static <T> Property<T> from(T value) {
if (value instanceof Boolean) { if (value instanceof Boolean)
return new Property<>(value, PropertyType.BOOLEAN); return new Property<>(value, PropertyType.BOOLEAN);
} else if (value instanceof Integer) { if (value instanceof Integer)
return new Property<>(value, PropertyType.INTEGER); return new Property<>(value, PropertyType.INTEGER);
} else if (value instanceof Float) { if (value instanceof Float)
return new Property<>(value, PropertyType.FLOAT); return new Property<>(value, PropertyType.FLOAT);
} else if (value instanceof String) { if (value instanceof String)
return new Property<>(value, PropertyType.STRING); return new Property<>(value, PropertyType.STRING);
} else if (valueIsNamespace(value)) { if (valueIsNamespace(value))
return new Property<>(value, PropertyType.NAMESPACE); return new Property<>(value, PropertyType.NAMESPACE);
} else { return null;
return null;
}
}
public Property<T> copy() {
return new Property<>(this.value, this.type);
} }
public static Property<Integer> font(int value) { public static Property<Integer> font(int value) {
@@ -92,55 +88,37 @@ public class Property<T> {
return new Property<>(value, PropertyType.KEYBINDING); return new Property<>(value, PropertyType.KEYBINDING);
} }
// ---------- Select Helpers ----------
public void next() { public void next() {
if ((Integer) value < availableValues.length - 1) if (type == PropertyType.SELECT) {
setValue((Integer) value + 1); int i = (Integer) value;
else setValue((i < availableValues.length - 1) ? i + 1 : 0);
setValue(0); }
} }
public void prev() { public void prev() {
if ((Integer) value > 0) if (type == PropertyType.SELECT) {
setValue((Integer) value - 1); int i = (Integer) value;
else setValue((i > 0) ? i - 1 : availableValues.length - 1);
setValue(availableValues.length - 1); }
} }
public void setSelection(int selection) { public void setSelection(int selection) {
if (selection >= 0 && selection < availableValues.length && type == PropertyType.SELECT) { if (type == PropertyType.SELECT && selection >= 0 && selection < availableValues.length) {
setValue(selection); setValue(selection);
} }
} }
public String getSelection() { public String getSelection() {
if (type == PropertyType.SELECT) { return (type == PropertyType.SELECT) ? availableValues[(Integer) value] : null;
return availableValues[(Integer) value];
} else {
return null;
}
} }
// ---------- Lifecycle ----------
public void reset() { public void reset() {
value = defaultValue; value = defaultValue;
isReset = true; isReset = true;
} }
public int getHexString() {
if (value instanceof String) {
String str = (String) value;
if (str.startsWith("0x") || str.startsWith("0X")) {
try {
return Integer.parseInt(str.substring(2), 16);
} catch (NumberFormatException e) {
throw new IllegalStateException(
"Invalid hexadecimal integer format");
}
}
}
throw new IllegalStateException(
"Property does not contain a valid hex integer");
}
public PropertyType getType() { public PropertyType getType() {
return type; return type;
} }
@@ -153,34 +131,93 @@ public class Property<T> {
throw new IllegalStateException("Property is not a namespace"); throw new IllegalStateException("Property is not a namespace");
} }
public boolean matchesJson(JsonElement element) { // ---------- JSON Serialization ----------
if (element.isJsonPrimitive()) { /*
JsonPrimitive primitive = element.getAsJsonPrimitive(); * BOOLEAN,
if (value instanceof Boolean && primitive.isBoolean()) * INTEGER,
return true; * FLOAT,
if (value instanceof Integer && primitive.isNumber()) * STRING,
return true; * HEX,
if (value instanceof Float && primitive.isNumber()) * NAMESPACE,
return true; * SELECT,
if (value instanceof String && primitive.isString()) * KEYBINDING,
return true; */
if (type == PropertyType.HEX && primitive.isString()) public JsonElement toJson() {
return true; switch (type) {
} else if (element.isJsonObject()) { case BOOLEAN:
return isNamespace(value); return new JsonPrimitive((Boolean) value);
case INTEGER:
return new JsonPrimitive((Integer) value);
case FLOAT:
return new JsonPrimitive((Float) value);
case NAMESPACE:
JsonObject nested = new JsonObject();
getNamespaceValue().forEach((k, v) -> nested.add(k, v.toJson()));
return nested;
case HEX:
return new JsonPrimitive(String.format("#%08X", (Integer) value));
case KEYBINDING:
return new JsonPrimitive((Integer) value);
case SELECT:
return new JsonPrimitive((Integer) value);
default:
return new JsonPrimitive(String.valueOf(value));
} }
return false;
} }
public void loadFromJson(JsonElement element) {
if (element == null)
return;
switch (type) {
case BOOLEAN:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isBoolean())
setValue(element.getAsBoolean());
break;
case INTEGER:
if (element.isJsonPrimitive()) {
JsonPrimitive p = element.getAsJsonPrimitive();
if (p.isNumber())
setValue(p.getAsInt());
else if (p.isString())
setValue(parseHexToInt(p.getAsString()));
}
break;
case FLOAT:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber())
setValue(element.getAsFloat());
break;
case STRING:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString())
setValue(element.getAsString());
break;
case HEX:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString())
setValue(parseHexToInt(element.getAsString()));
break;
case NAMESPACE:
if (element.isJsonObject()) {
JsonObject obj = element.getAsJsonObject();
getNamespaceValue().forEach((k, v) -> v.loadFromJson(obj.get(k)));
}
break;
case SELECT:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber())
setSelection(element.getAsInt());
break;
case KEYBINDING:
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber())
setValue(element.getAsInt());
break;
}
}
// ---------- Utility ----------
@Override @Override
public String toString() { public String toString() {
return String.valueOf(value); return String.valueOf(value);
} }
public boolean isNamespace(Object obj) {
return type == PropertyType.NAMESPACE && value instanceof Map;
}
public static boolean valueIsNamespace(Object obj) { public static boolean valueIsNamespace(Object obj) {
return obj instanceof Map; return obj instanceof Map;
} }
@@ -200,59 +237,44 @@ public class Property<T> {
return new NamedProperty<>(name, this); return new NamedProperty<>(name, this);
} }
// ---------- Keybindings ----------
public boolean isKeyPressed() { public boolean isKeyPressed() {
return (Integer) value == -1 ? false return (Integer) value != -1 &&
: GLFW.glfwGetKey(SaturnClient.client.getWindow().getHandle(), GLFW.glfwGetKey(SaturnClient.client.getWindow().getHandle(), (Integer) value) == GLFW.GLFW_PRESS &&
(Integer) (Object) value) == GLFW.GLFW_PRESS && SaturnClient.client.currentScreen == null; SaturnClient.client.currentScreen == null;
} }
public boolean wasKeyPressed() { public boolean wasKeyPressed() {
boolean isPressed = this.isKeyPressed(); boolean pressed = isKeyPressed();
wasPressedLastTick = isPressed && !wasPressedLastTick; boolean result = pressed && !wasPressedLastTick;
return wasPressedLastTick; wasPressedLastTick = pressed;
} return result;
@SuppressWarnings("unchecked")
public void load(String name, JsonElement element) {
if (element != null && element.isJsonObject()) {
JsonElement value = element.getAsJsonObject().get(name);
if (value != null) {
switch (this.getType()) {
case BOOLEAN:
((Property<Boolean>) this).setValue(value.getAsBoolean());
break;
case INTEGER:
JsonPrimitive primitive = value.getAsJsonPrimitive();
if (primitive.isNumber())
((Property<Integer>) this).setValue(value.getAsInt());
else if (primitive.isString())
((Property<Integer>) this).setValue(parseHexToInt(value.getAsString()));
break;
case FLOAT:
((Property<Float>) this).setValue(value.getAsFloat());
break;
case STRING:
((Property<String>) this).setValue(value.getAsString());
break;
case HEX:
((Property<Integer>) this).setValue(parseHexToInt(value.getAsString()));
break;
default:
break;
}
}
}
} }
// ---------- HEX ----------
public static int parseHexToInt(String hex) { public static int parseHexToInt(String hex) {
hex = hex.replaceAll("#", ""); hex = hex.replace("#", "");
if (hex.length() == 6)
if (hex.length() == 6) {
hex = "FF" + hex; hex = "FF" + hex;
} else if (hex.length() != 8) { if (hex.length() != 8)
throw new IllegalArgumentException("Hex string must be 6 or 8 characters long"); throw new IllegalArgumentException("Hex must be 6 or 8 chars long, got \'" + hex + "\'");
}
return (int) Long.parseLong(hex, 16); return (int) Long.parseLong(hex, 16);
} }
// Misc
public Property<T> copy() {
return new Property<>(this.value, this.type);
}
public void load(String name, JsonElement element) {
if (element != null && element.isJsonObject()) {
load(name, element.getAsJsonObject());
}
}
public void load(String name, JsonObject element) {
JsonElement value = element.get(name);
if (value != null)
this.loadFromJson(value);
}
} }
@@ -26,7 +26,7 @@ public class HudEditor extends Screen {
public HudEditor() { public HudEditor() {
super(Text.literal("HUD Editor")); super(Text.literal("HUD Editor"));
for (Module m : ModManager.MODS) { for (Module m : ModManager.ENABLED_MODS) {
if (m.isEnabled() && m instanceof HudMod) { if (m.isEnabled() && m instanceof HudMod) {
hudMods.add((HudMod) m); hudMods.add((HudMod) m);
} }
@@ -58,13 +58,15 @@ public class RenderScope {
int newAlpha = (opacity >>> 24) & 0xFF; int newAlpha = (opacity >>> 24) & 0xFF;
int mixedAlpha = (originalAlpha * newAlpha) / 255; int mixedAlpha = (originalAlpha * newAlpha) / 255;
return (mixedAlpha << 24) | (color & 0x00FFFFFF); return (mixedAlpha << 24) | (color & 0x00FFFFFF);
} }
public void setRenderLayer(Function<Identifier, RenderLayer> renderLayers) { public void setRenderLayer(Function<Identifier, RenderLayer> renderLayers) {
// this.renderLayers = renderLayers; // this.renderLayers = renderLayers;
} }
public void drawRect(int x, int y, int width, int height, int color) { public void drawRect(int x, int y, int width, int height, int color) {
if (color == 0)
return;
color = getColor(color); color = getColor(color);
Matrix4f matrix4f = this.matrices.peek().getPositionMatrix(); Matrix4f matrix4f = this.matrices.peek().getPositionMatrix();
@@ -98,6 +100,8 @@ public class RenderScope {
} }
public void drawText(float scale, String text, int x, int y, int font, int color) { public void drawText(float scale, String text, int x, int y, int font, int color) {
if (color == 0)
return;
if (font == 0) { if (font == 0) {
scale *= 2; scale *= 2;
} }
@@ -108,7 +112,8 @@ public class RenderScope {
matrices.translate(x, y + (i * Fonts.getHeight()), 0); matrices.translate(x, y + (i * Fonts.getHeight()), 0);
matrices.scale(scale, scale, 1.0f); matrices.scale(scale, scale, 1.0f);
TextRenderer textRenderer = SaturnClient.client.textRenderer; TextRenderer textRenderer = SaturnClient.client.textRenderer;
textRenderer.draw(Fonts.setFont(line, Fonts.getFont(font)), 0, font == 0 ? 1: 7, color, false, this.matrices.peek().getPositionMatrix(), textRenderer.draw(Fonts.setFont(line, Fonts.getFont(font)), 0, font == 0 ? 1 : 7, color, false,
this.matrices.peek().getPositionMatrix(),
this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880); this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880);
matrices.pop(); matrices.pop();
i++; i++;
@@ -118,19 +123,19 @@ public class RenderScope {
private void drawRoundedCorner(int width, int height, int radius, int color) { private void drawRoundedCorner(int width, int height, int radius, int color) {
int w = width * 20; int w = width * 20;
int h = height * 20; int h = height * 20;
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
int startX = 0; int startX = 0;
if (y < radius) { if (y < radius) {
double dy = radius - y - 0.5; double dy = radius - y - 0.5;
double dx = Math.sqrt(Math.max(0, radius * radius - dy * dy)); double dx = Math.sqrt(Math.max(0, radius * radius - dy * dy));
startX = radius - (int) dx; startX = radius - (int) dx;
} }
this.drawRect(startX, y, w - startX, 1, color); this.drawRect(startX, y, w - startX, 1, color);
} }
} }
private void drawRoundedSide(int cornerWidth, int cornerHeight, int radius, int color) { private void drawRoundedSide(int cornerWidth, int cornerHeight, int radius, int color) {
// Top // Top
@@ -159,6 +164,8 @@ public class RenderScope {
} }
public void drawRoundedRectangle(int x, int y, int width, int height, int radius, int color) { public void drawRoundedRectangle(int x, int y, int width, int height, int radius, int color) {
if (color == 0)
return;
radius = Math.min(radius, Math.min(width, height)); radius = Math.min(radius, Math.min(width, height));
int cornerWidth = width / 2; int cornerWidth = width / 2;
int cornerHeight = height / 2; int cornerHeight = height / 2;
@@ -183,27 +190,35 @@ public class RenderScope {
public int getScaledWindowWidth() { public int getScaledWindowWidth() {
return SaturnClient.client.getWindow().getScaledWidth(); return SaturnClient.client.getWindow().getScaledWidth();
} }
public int getScaledWindowHeight() { public int getScaledWindowHeight() {
return SaturnClient.client.getWindow().getScaledHeight(); return SaturnClient.client.getWindow().getScaledHeight();
} }
public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int color) { public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int color) {
this.drawTexture(sprite, x, y, u, v, width, height, width, height, width, height, color); this.drawTexture(sprite, x, y, u, v, width, height, width, height, width, height, color);
} }
public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height) { public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height) {
this.drawTexture(sprite, x, y, u, v, width, height, width, height, width, height); this.drawTexture(sprite, x, y, u, v, width, height, width, height, width, height);
} }
public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWith, int regionHeight, int textureWidth, int textureHeight) { public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWith,
this.drawTexture(sprite, x, y, u, v, width, height, regionWith, regionHeight, textureWidth, textureHeight, -1); int regionHeight, int textureWidth, int textureHeight) {
this.drawTexture(sprite, x, y, u, v, width, height, regionWith, regionHeight, textureWidth, textureHeight, -1);
} }
public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color) { public void drawTexture(Identifier sprite, int x, int y, float u, float v, int width, int height, int regionWidth,
this.drawTexturedQuad(sprite, x, x + width, y, y + height, (u + 0.0F) / (float)textureWidth, (u + (float)regionWidth) / (float)textureWidth, (v + 0.0F) / (float)textureHeight, (v + (float)regionHeight) / (float)textureHeight, color); int regionHeight, int textureWidth, int textureHeight, int color) {
this.drawTexturedQuad(sprite, x, x + width, y, y + height, (u + 0.0F) / (float) textureWidth,
(u + (float) regionWidth) / (float) textureWidth, (v + 0.0F) / (float) textureHeight,
(v + (float) regionHeight) / (float) textureHeight, color);
} }
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2, float u1, float u2, float v1, float v2, int color) { private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2, float u1, float u2, float v1,
float v2, int color) {
if (color == 0)
return;
x1 *= 4; x1 *= 4;
x2 *= 4; x2 *= 4;
y1 *= 4; y1 *= 4;
@@ -213,44 +228,45 @@ public class RenderScope {
matrices.push(); matrices.push();
matrices.scale(0.25f, 0.25f, 1.0f); matrices.scale(0.25f, 0.25f, 1.0f);
RenderSystem.setShaderTexture(0, sprite); RenderSystem.setShaderTexture(0, sprite);
RenderLayer renderLayer = (RenderLayer)RenderLayer.getGuiTextured(sprite); RenderLayer renderLayer = (RenderLayer) RenderLayer.getGuiTextured(sprite);
Matrix4f matrix4f = this.matrices.peek().getPositionMatrix(); Matrix4f matrix4f = this.matrices.peek().getPositionMatrix();
VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(renderLayer); VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(renderLayer);
vertexConsumer.vertex(matrix4f, (float)x1, (float)y1, 0.0F).texture(u1, v1).color(color); vertexConsumer.vertex(matrix4f, (float) x1, (float) y1, 0.0F).texture(u1, v1).color(color);
vertexConsumer.vertex(matrix4f, (float)x1, (float)y2, 0.0F).texture(u1, v2).color(color); vertexConsumer.vertex(matrix4f, (float) x1, (float) y2, 0.0F).texture(u1, v2).color(color);
vertexConsumer.vertex(matrix4f, (float)x2, (float)y2, 0.0F).texture(u2, v2).color(color); vertexConsumer.vertex(matrix4f, (float) x2, (float) y2, 0.0F).texture(u2, v2).color(color);
vertexConsumer.vertex(matrix4f, (float)x2, (float)y1, 0.0F).texture(u2, v1).color(color); vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, 0.0F).texture(u2, v1).color(color);
matrices.pop(); matrices.pop();
} }
public void enableScissor(int x1, int y1, int x2, int y2) { public void enableScissor(int x1, int y1, int x2, int y2) {
ScreenRect screenRect = (new ScreenRect(x1, y1, x2 - x1, y2 - y1)).transform(this.matrices.peek().getPositionMatrix()); ScreenRect screenRect = (new ScreenRect(x1, y1, x2 - x1, y2 - y1))
.transform(this.matrices.peek().getPositionMatrix());
this.setScissor(this.scissorStack.push(screenRect)); this.setScissor(this.scissorStack.push(screenRect));
} }
public void disableScissor() { public void disableScissor() {
this.setScissor(this.scissorStack.pop()); this.setScissor(this.scissorStack.pop());
} }
public boolean scissorContains(int x, int y) { public boolean scissorContains(int x, int y) {
return this.scissorStack.containsPoint(x, y); return this.scissorStack.containsPoint(x, y);
} }
private void setScissor(@Nullable ScreenRect rect) { private void setScissor(@Nullable ScreenRect rect) {
this.draw(); this.draw();
if (rect != null) { if (rect != null) {
Window window = SaturnClient.client.getWindow(); Window window = SaturnClient.client.getWindow();
int i = window.getFramebufferHeight(); int i = window.getFramebufferHeight();
double d = window.getScaleFactor(); double d = window.getScaleFactor();
double e = (double)rect.getLeft() * d; double e = (double) rect.getLeft() * d;
double f = (double)i - (double)rect.getBottom() * d; double f = (double) i - (double) rect.getBottom() * d;
double g = (double)rect.width() * d; double g = (double) rect.width() * d;
double h = (double)rect.height() * d; double h = (double) rect.height() * d;
RenderSystem.enableScissor((int)e, (int)f, Math.max(0, (int)g), Math.max(0, (int)h)); RenderSystem.enableScissor((int) e, (int) f, Math.max(0, (int) g), Math.max(0, (int) h));
} else { } else {
RenderSystem.disableScissor(); RenderSystem.disableScissor();
} }
} }
public void draw() { public void draw() {
@@ -260,7 +276,7 @@ public class RenderScope {
public void draw(Consumer<VertexConsumerProvider> drawer) { public void draw(Consumer<VertexConsumerProvider> drawer) {
drawer.accept(this.vertexConsumers); drawer.accept(this.vertexConsumers);
this.vertexConsumers.draw(); this.vertexConsumers.draw();
} }
static class ScissorStack { static class ScissorStack {
private final Deque<ScreenRect> stack = new ArrayDeque<>(); private final Deque<ScreenRect> stack = new ArrayDeque<>();
@@ -268,7 +284,8 @@ public class RenderScope {
public ScreenRect push(ScreenRect p_281812_) { public ScreenRect push(ScreenRect p_281812_) {
ScreenRect screenrectangle = this.stack.peekLast(); ScreenRect screenrectangle = this.stack.peekLast();
if (screenrectangle != null) { if (screenrectangle != null) {
ScreenRect screenrectangle1 = Objects.requireNonNullElse(p_281812_.intersection(screenrectangle), ScreenRect.empty()); ScreenRect screenrectangle1 = Objects.requireNonNullElse(p_281812_.intersection(screenrectangle),
ScreenRect.empty());
this.stack.addLast(screenrectangle1); this.stack.addLast(screenrectangle1);
return screenrectangle1; return screenrectangle1;
} else { } else {
@@ -309,47 +326,51 @@ public class RenderScope {
} }
public void drawItemWithoutEntity(ItemStack stack, int x, int y, int seed) { public void drawItemWithoutEntity(ItemStack stack, int x, int y, int seed) {
this.drawItem((LivingEntity)null, SaturnClient.client.world, stack, x, y, seed); this.drawItem((LivingEntity) null, SaturnClient.client.world, stack, x, y, seed);
} }
public void drawItem(LivingEntity entity, ItemStack stack, int x, int y, int seed) { public void drawItem(LivingEntity entity, ItemStack stack, int x, int y, int seed) {
this.drawItem(entity, entity.getWorld(), stack, x, y, seed); this.drawItem(entity, entity.getWorld(), stack, x, y, seed);
} }
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed) { private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y,
int seed) {
this.drawItem(entity, world, stack, x, y, seed, 0); this.drawItem(entity, world, stack, x, y, seed, 0);
} }
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed, int z) { private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed,
int z) {
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
SaturnClient.client.getItemModelManager().update(this.itemRenderState, stack, ModelTransformationMode.GUI, false, world, entity, seed); SaturnClient.client.getItemModelManager().update(this.itemRenderState, stack, ModelTransformationMode.GUI,
false, world, entity, seed);
this.matrices.push(); this.matrices.push();
this.matrices.translate((float)(x + 8), (float)(y + 8), (float)(150 + (this.itemRenderState.hasDepth() ? z : 0))); this.matrices.translate((float) (x + 8), (float) (y + 8),
(float) (150 + (this.itemRenderState.hasDepth() ? z : 0)));
try { try {
this.matrices.scale(16.0F, -16.0F, 16.0F); this.matrices.scale(16.0F, -16.0F, 16.0F);
boolean bl = !this.itemRenderState.isSideLit(); boolean bl = !this.itemRenderState.isSideLit();
if (bl) { if (bl) {
this.draw(); this.draw();
DiffuseLighting.disableGuiDepthLighting(); DiffuseLighting.disableGuiDepthLighting();
} }
this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV); this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV);
this.draw(); this.draw();
if (bl) { if (bl) {
DiffuseLighting.enableGuiDepthLighting(); DiffuseLighting.enableGuiDepthLighting();
} }
} catch (Throwable var11) { } catch (Throwable var11) {
CrashReport crashReport = CrashReport.create(var11, "Rendering item"); CrashReport crashReport = CrashReport.create(var11, "Rendering item");
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered"); CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
crashReportSection.add("Item Type", () -> { crashReportSection.add("Item Type", () -> {
return String.valueOf(stack.getItem()); return String.valueOf(stack.getItem());
}); });
crashReportSection.add("Item Components", () -> { crashReportSection.add("Item Components", () -> {
return String.valueOf(stack.getComponents()); return String.valueOf(stack.getComponents());
}); });
crashReportSection.add("Item Foil", () -> { crashReportSection.add("Item Foil", () -> {
return String.valueOf(stack.hasGlint()); return String.valueOf(stack.hasGlint());
}); });
throw new CrashException(crashReport); throw new CrashException(crashReport);
} }
@@ -363,8 +384,11 @@ public class RenderScope {
} }
public void drawSpriteStretched(Sprite sprite, int x, int y, int width, int height, int color) { public void drawSpriteStretched(Sprite sprite, int x, int y, int width, int height, int color) {
if (color == 0)
return;
if (width != 0 && height != 0) { if (width != 0 && height != 0) {
this.drawTexturedQuad(sprite.getAtlasId(), x, x + width, y, y + height, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV(), color); this.drawTexturedQuad(sprite.getAtlasId(), x, x + width, y, y + height, sprite.getMinU(), sprite.getMaxU(),
sprite.getMinV(), sprite.getMaxV(), color);
} }
} }
} }
@@ -23,8 +23,8 @@ public class ModMenu extends SaturnScreen {
int row = 0; int row = 0;
int col = 0; int col = 0;
for (Module mod : ModManager.MODS) { for (Module mod : ModManager.ALL_MODS) {
scroll.draw(new SaturnModule(mod).position((160 + g) * col, (50 + g) * row)); scroll.draw(new SaturnModule(mod).position((160 + g) * col, (50 + g) * row));
if (col == 2) { if (col == 2) {
@@ -36,7 +36,7 @@ public class ModMenu extends SaturnScreen {
} }
int scrollWidth = 480 + 10 + (g * 2) + (p * 2); int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height)); draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));