From 2a0b8b6cfa683e0514294a4ea0429429537f380f Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Fri, 19 Dec 2025 17:39:37 +0000 Subject: [PATCH 1/2] fix bad wording --- packages/ui/src/components/base/DropzoneFileInput.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/base/DropzoneFileInput.vue b/packages/ui/src/components/base/DropzoneFileInput.vue index 616ac6dcb6..559cd3a533 100644 --- a/packages/ui/src/components/base/DropzoneFileInput.vue +++ b/packages/ui/src/components/base/DropzoneFileInput.vue @@ -71,7 +71,7 @@ const props = withDefaults( { prompt: 'Drag and drop files or click to browse', primaryPrompt: 'Drag and drop files or click to browse', - secondaryPrompt: 'You can try to drag files or folder or click this area to select it', + secondaryPrompt: 'You can drag files or folders here, or click this area to select file(s) for upload.', size: 'standard', }, ) From 9c3d05e2d163bde0e8fab66734bb8edbee55fe57 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Sun, 21 Dec 2025 15:56:58 +0000 Subject: [PATCH 2/2] actually run pnpm fix (should merge now?) --- apps/app/Cargo.toml | 6 +- apps/daedalus_client/Cargo.toml | 18 +- apps/labrinth/Cargo.toml | 69 +- .../fixtures/delphi-report-2025-11-15.sql | 711 +++++++++++++++++- ...251024182919_subscription_affiliations.sql | 20 +- ...0125413_decouple_threads_from_projects.sql | 5 +- .../20251130173416_delphi_report_verdicts.sql | 2 +- .../20251201171345_store_ids_as_text.sql | 22 +- ...47_delphi_dedupe_issue_detail_statuses.sql | 32 +- packages/app-lib/Cargo.toml | 70 +- .../20251002173041_settings-version.sql | 2 +- packages/assets/generated-icons.ts | 46 +- packages/blog/compiled/index.ts | 64 +- .../src/components/base/DropzoneFileInput.vue | 3 +- 14 files changed, 858 insertions(+), 212 deletions(-) diff --git a/apps/app/Cargo.toml b/apps/app/Cargo.toml index 4a07f2a1c0..ee64ce2767 100644 --- a/apps/app/Cargo.toml +++ b/apps/app/Cargo.toml @@ -21,11 +21,7 @@ path-util = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_with = { workspace = true } -tauri = { workspace = true, features = [ - "devtools", - "macos-private-api", - "protocol-asset", -] } +tauri = { workspace = true, features = ["devtools", "macos-private-api", "protocol-asset"] } tauri-plugin-deep-link = { workspace = true } tauri-plugin-dialog = { workspace = true } tauri-plugin-http = { workspace = true } diff --git a/apps/daedalus_client/Cargo.toml b/apps/daedalus_client/Cargo.toml index 1f6aa350df..5076dc7960 100644 --- a/apps/daedalus_client/Cargo.toml +++ b/apps/daedalus_client/Cargo.toml @@ -5,12 +5,12 @@ edition.workspace = true [dependencies] async_zip = { workspace = true, features = [ - "bzip2", - "chrono", - "deflate", - "deflate64", - "tokio-fs", - "zstd", + "bzip2", + "chrono", + "deflate", + "deflate64", + "tokio-fs", + "zstd", ] } bytes = { workspace = true } chrono = { workspace = true, features = ["serde"] } @@ -20,11 +20,7 @@ dotenvy = { workspace = true } futures = { workspace = true } indexmap = { workspace = true, features = ["serde"] } itertools = { workspace = true } -reqwest = { workspace = true, features = [ - "json", - "rustls-tls-native-roots", - "stream", -] } +reqwest = { workspace = true, features = ["json", "rustls-tls-native-roots", "stream"] } rust-s3 = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml index f267cc59ad..3066f1af73 100644 --- a/apps/labrinth/Cargo.toml +++ b/apps/labrinth/Cargo.toml @@ -21,12 +21,7 @@ actix-ws = { workspace = true } arc-swap = { workspace = true } argon2 = { workspace = true } ariadne = { workspace = true } -async-stripe = { workspace = true, features = [ - "billing", - "checkout", - "connect", - "webhook-events", -] } +async-stripe = { workspace = true, features = ["billing", "checkout", "connect", "webhook-events"] } async-trait = { workspace = true } base64 = { workspace = true } bitflags = { workspace = true } @@ -50,21 +45,21 @@ hmac = { workspace = true } hyper-rustls = { workspace = true } hyper-util = { workspace = true } image = { workspace = true, features = [ - "avif", - "bmp", - "dds", - "exr", - "ff", - "gif", - "hdr", - "ico", - "jpeg", - "png", - "pnm", - "qoi", - "tga", - "tiff", - "webp", + "avif", + "bmp", + "dds", + "exr", + "ff", + "gif", + "hdr", + "ico", + "jpeg", + "png", + "pnm", + "qoi", + "tga", + "tiff", + "webp", ] } itertools = { workspace = true } json-patch = { workspace = true } @@ -81,16 +76,8 @@ rand = { workspace = true } rand_chacha = { workspace = true } redis = { workspace = true, features = ["ahash", "r2d2", "tokio-comp"] } regex = { workspace = true } -reqwest = { workspace = true, features = [ - "http2", - "json", - "multipart", - "rustls-tls-webpki-roots", -] } -rust_decimal = { workspace = true, features = [ - "serde-with-float", - "serde-with-str", -] } +reqwest = { workspace = true, features = ["http2", "json", "multipart", "rustls-tls-webpki-roots"] } +rust_decimal = { workspace = true, features = ["serde-with-float", "serde-with-str"] } rust_iso3166 = { workspace = true } rust-s3 = { workspace = true } rustls.workspace = true @@ -104,14 +91,14 @@ sha1 = { workspace = true } sha2 = { workspace = true } spdx = { workspace = true, features = ["text"] } sqlx = { workspace = true, features = [ - "chrono", - "json", - "macros", - "migrate", - "postgres", - "runtime-tokio", - "rust_decimal", - "tls-rustls-aws-lc-rs", + "chrono", + "json", + "macros", + "migrate", + "postgres", + "runtime-tokio", + "rust_decimal", + "tls-rustls-aws-lc-rs", ] } strum = { workspace = true } thiserror = { workspace = true } @@ -145,8 +132,8 @@ iana-time-zone = { workspace = true } jemalloc_pprof = { workspace = true, features = ["flamegraph"] } tikv-jemalloc-ctl = { workspace = true, features = ["stats"] } tikv-jemallocator = { workspace = true, features = [ - "profiling", - "unprefixed_malloc_on_supported_platforms", + "profiling", + "unprefixed_malloc_on_supported_platforms", ] } [features] diff --git a/apps/labrinth/fixtures/delphi-report-2025-11-15.sql b/apps/labrinth/fixtures/delphi-report-2025-11-15.sql index 389159672a..0a84a299c0 100644 --- a/apps/labrinth/fixtures/delphi-report-2025-11-15.sql +++ b/apps/labrinth/fixtures/delphi-report-2025-11-15.sql @@ -13,7 +13,7 @@ SET idle_in_transaction_session_timeout = 0; SET transaction_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); +SELECT pg_catalog.set_config('search_path', '', FALSE); SET check_function_bodies = false; SET xmloption = content; SET client_min_messages = warning; @@ -29,7 +29,10 @@ COPY public.delphi_reports (id, file_id, delphi_version, artifact_url, created, -- --- Data for Name: delphi_report_issues; Type: TABLE DATA; Schema: public; Owner: labrinth +-- Data for Name: delphi_report_issues; +Type: TABLE DATA; +Schema: public; +Owner: labrinth -- COPY public.delphi_report_issues (id, report_id, issue_type, status) FROM stdin; @@ -42,49 +45,715 @@ COPY public.delphi_report_issues (id, report_id, issue_type, status) FROM stdin; -- --- Data for Name: delphi_report_issue_details; Type: TABLE DATA; Schema: public; Owner: labrinth +-- Data for Name: delphi_report_issue_details; +Type: TABLE DATA; +Schema: public; +Owner: labrinth -- COPY public.delphi_report_issue_details (id, issue_id, key, file_path, decompiled_source, data, severity) FROM stdin; -1 1 d670186a0e5210fc2b9332a2163849740f19bec59a99d890bef0ae9e6608f83d net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl package net.caffeinemc.mods.sodium.desktop.utils.browse;\n\nimport java.io.IOException;\nimport java.util.Locale;\n\nclass XDGImpl implements BrowseUrlHandler {\n public static boolean isSupported() {\n String os = System.getProperty("os.name").toLowerCase(Locale.ROOT);\n return os.equals("linux");\n }\n\n @Override\n public void browseTo(String url) throws IOException {\n Process process = Runtime.getRuntime().exec(new String[]{"xdg-open", url});\n\n try {\n int result = process.waitFor();\n if (result != 0) {\n throw new IOException("xdg-open exited with code: %d".formatted(result));\n }\n } catch (InterruptedException var4) {\n throw new RuntimeException(var4);\n }\n }\n}\n {} medium -2 1 317dd815f60f04f1cef5d855e30f6a2719570c583ef49ae94ca2b563179fc1fa net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe package net.caffeinemc.mods.sodium.client.compatibility.environment.probe;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.OsUtils;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMT;\nimport org.jetbrains.annotations.Nullable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class GraphicsAdapterProbe {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-GraphicsAdapterProbe");\n private static final Set LINUX_PCI_CLASSES = Set.of("0x030000", "0x030001", "0x030200", "0x038000");\n private static List ADAPTERS = List.of();\n\n public static void findAdapters() {\n LOGGER.info("Searching for graphics cards...");\n\n List adapters;\n try {\n adapters = switch (OsUtils.getOs()) {\n case WIN -> findAdapters$Windows();\n case LINUX -> findAdapters$Linux();\n default -> null;\n };\n } catch (Exception var3) {\n LOGGER.error("Failed to find graphics adapters!", var3);\n return;\n }\n\n if (adapters != null) {\n if (adapters.isEmpty()) {\n LOGGER.warn(\n "Could not find any graphics adapters! Probably the device is not on a bus we can probe, or there are no devices supporting 3D acceleration."\n );\n } else {\n for (GraphicsAdapterInfo adapter : adapters) {\n LOGGER.info("Found graphics adapter: {}", adapter);\n }\n }\n\n ADAPTERS = adapters;\n }\n }\n\n private static List findAdapters$Windows() {\n return D3DKMT.findGraphicsAdapters();\n }\n\n private static List findAdapters$Linux() {\n ArrayList results = new ArrayList();\n\n try {\n Stream devices = Files.list(Path.of("/sys/bus/pci/devices/"));\n\n try {\n for (Path devicePath : devices::iterator) {\n String deviceClass = Files.readString(devicePath.resolve("class")).trim();\n if (LINUX_PCI_CLASSES.contains(deviceClass)) {\n String pciVendorId = Files.readString(devicePath.resolve("vendor")).trim();\n String pciDeviceId = Files.readString(devicePath.resolve("device")).trim();\n GraphicsAdapterVendor adapterVendor = GraphicsAdapterVendor.fromPciVendorId(pciVendorId);\n String adapterName = getPciDeviceName$Linux(pciVendorId, pciDeviceId);\n if (adapterName == null) {\n adapterName = "";\n }\n\n GraphicsAdapterInfo.LinuxPciAdapterInfo info = new GraphicsAdapterInfo.LinuxPciAdapterInfo(\n adapterVendor, adapterName, pciVendorId, pciDeviceId\n );\n results.add(info);\n }\n }\n } catch (Throwable var12) {\n if (devices != null) {\n try {\n devices.close();\n } catch (Throwable var11) {\n var12.addSuppressed(var11);\n }\n }\n\n throw var12;\n }\n\n if (devices != null) {\n devices.close();\n }\n } catch (IOException var13) {\n }\n\n return results;\n }\n\n @Nullable\n private static String getPciDeviceName$Linux(String vendorId, String deviceId) {\n String deviceFilter = vendorId.substring(2) + ":" + deviceId.substring(2);\n\n try {\n Process process = Runtime.getRuntime().exec(new String[]{"lspci", "-vmm", "-d", deviceFilter});\n int result = process.waitFor();\n if (result != 0) {\n throw new IOException("lspci exited with error code: %s".formatted(result));\n } else {\n BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));\n\n String var7;\n label40: {\n String line;\n try {\n while ((line = reader.readLine()) != null) {\n if (line.startsWith("Device:")) {\n var7 = line.substring("Device:".length()).trim();\n break label40;\n }\n }\n } catch (Throwable var9) {\n try {\n reader.close();\n } catch (Throwable var8) {\n var9.addSuppressed(var8);\n }\n\n throw var9;\n }\n\n reader.close();\n throw new IOException("lspci did not return a device name");\n }\n\n reader.close();\n return var7;\n }\n } catch (Throwable var10) {\n LOGGER.warn("Failed to query PCI device name for %s:%s".formatted(vendorId, deviceId), var10);\n return null;\n }\n }\n\n public static Collection getAdapters() {\n if (ADAPTERS == null) {\n LOGGER.error("Graphics adapters not probed yet; returning an empty list.");\n return Collections.emptyList();\n } else {\n return ADAPTERS;\n }\n }\n}\n {} medium -3 2 5ba58b7f9dcc59f14c8a0fd9b78c23a19723791bd9006ed408d43557ea24abb4 net/caffeinemc/mods/sodium/desktop/LaunchWarn package net.caffeinemc.mods.sodium.desktop;\n\nimport java.awt.GraphicsEnvironment;\nimport java.io.IOException;\nimport javax.swing.JDialog;\nimport javax.swing.JOptionPane;\nimport javax.swing.UIManager;\nimport javax.swing.UnsupportedLookAndFeelException;\nimport net.caffeinemc.mods.sodium.desktop.utils.browse.BrowseUrlHandler;\n\npublic class LaunchWarn {\n private static final String HELP_URL = "https://link.caffeinemc.net/guides/sodium/installation";\n private static final String RICH_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

";\n private static final String FALLBACK_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

";\n private static final String FAILED_TO_BROWSE_MESSAGE = "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

";\n public static final String WINDOW_TITLE = "Sodium";\n\n public static void main(String[] args) {\n if (GraphicsEnvironment.isHeadless()) {\n showHeadlessError();\n } else {\n showGraphicalError();\n }\n }\n\n private static void showHeadlessError() {\n System.err\n .println(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"\n );\n }\n\n private static void showGraphicalError() {\n trySetSystemLookAndFeel();\n trySetSystemFontPreferences();\n BrowseUrlHandler browseUrlHandler = BrowseUrlHandler.createImplementation();\n if (browseUrlHandler != null) {\n showRichGraphicalDialog(browseUrlHandler);\n } else {\n showFallbackGraphicalDialog();\n }\n\n System.exit(0);\n }\n\n private static void showRichGraphicalDialog(BrowseUrlHandler browseUrlHandler) {\n int selectedOption = showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

",\n "Sodium",\n 0,\n 1,\n new String[]{"Help", "Close"},\n 0\n );\n if (selectedOption == 0) {\n log("Opening URL: https://link.caffeinemc.net/guides/sodium/installation");\n\n try {\n browseUrlHandler.browseTo("https://link.caffeinemc.net/guides/sodium/installation");\n } catch (IOException var3) {\n log("Failed to open default web browser!", var3);\n showDialogBox(\n "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

",\n "Sodium",\n -1,\n 2,\n null,\n -1\n );\n }\n }\n }\n\n private static void showFallbackGraphicalDialog() {\n showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

",\n "Sodium",\n -1,\n 1,\n null,\n null\n );\n }\n\n private static int showDialogBox(String message, String title, int optionType, int messageType, String[] options, Object initialValue) {\n JOptionPane pane = new JOptionPane(message, messageType, optionType, null, options, initialValue);\n JDialog dialog = pane.createDialog(title);\n dialog.setVisible(true);\n Object selectedValue = pane.getValue();\n if (selectedValue == null) {\n return -1;\n } else if (options == null) {\n return selectedValue instanceof Integer ? (Integer)selectedValue : -1;\n } else {\n for (int counter = 0; counter < options.length; counter++) {\n String option = options[counter];\n if (option.equals(selectedValue)) {\n return counter;\n }\n }\n\n return -1;\n }\n }\n\n private static void trySetSystemLookAndFeel() {\n try {\n UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\n } catch (UnsupportedLookAndFeelException | ReflectiveOperationException var1) {\n }\n }\n\n private static void trySetSystemFontPreferences() {\n System.setProperty("awt.useSystemAAFontSettings", "on");\n }\n\n private static void log(String message) {\n System.err.println(message);\n }\n\n private static void log(String message, Throwable exception) {\n System.err.println(message);\n exception.printStackTrace(System.err);\n }\n}\n {"url": "https://link.caffeinemc.net/guides/sodium/installation"} low -4 2 34a4ceb119311f669d4b3b036dfef9f93c1e86f765582ebf556b92486766f861 net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI package net.caffeinemc.mods.sodium.client.gui;\n\nimport com.google.common.collect.UnmodifiableIterator;\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.stream.Stream;\nimport net.caffeinemc.mods.sodium.client.SodiumClientMod;\nimport net.caffeinemc.mods.sodium.client.console.Console;\nimport net.caffeinemc.mods.sodium.client.console.message.MessageLevel;\nimport net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint;\nimport net.caffeinemc.mods.sodium.client.gui.options.Option;\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionFlag;\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionGroup;\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionImpact;\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionPage;\nimport net.caffeinemc.mods.sodium.client.gui.options.control.Control;\nimport net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement;\nimport net.caffeinemc.mods.sodium.client.gui.options.storage.OptionStorage;\nimport net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPrompt;\nimport net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPromptable;\nimport net.caffeinemc.mods.sodium.client.gui.screen.ConfigCorruptedScreen;\nimport net.caffeinemc.mods.sodium.client.gui.widgets.AbstractWidget;\nimport net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget;\nimport net.caffeinemc.mods.sodium.client.services.PlatformRuntimeInformation;\nimport net.caffeinemc.mods.sodium.client.util.Dim2i;\nimport net.minecraft.class_124;\nimport net.minecraft.class_156;\nimport net.minecraft.class_2561;\nimport net.minecraft.class_310;\nimport net.minecraft.class_332;\nimport net.minecraft.class_364;\nimport net.minecraft.class_437;\nimport net.minecraft.class_446;\nimport net.minecraft.class_5250;\nimport net.minecraft.class_5348;\nimport net.minecraft.class_5481;\nimport org.jetbrains.annotations.Nullable;\n\npublic class SodiumOptionsGUI extends class_437 implements ScreenPromptable {\n private final List pages = new ArrayList();\n private final List> controls = new ArrayList();\n private final class_437 prevScreen;\n private OptionPage currentPage;\n private FlatButtonWidget applyButton;\n private FlatButtonWidget closeButton;\n private FlatButtonWidget undoButton;\n private FlatButtonWidget donateButton;\n private FlatButtonWidget hideDonateButton;\n private boolean hasPendingChanges;\n private ControlElement hoveredElement;\n @Nullable\n private ScreenPrompt prompt;\n private static final List DONATION_PROMPT_MESSAGE = List.of(\n class_5348.method_29433(new class_5348[]{class_2561.method_43470("Hello!")}),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("It seems that you've been enjoying "),\n class_2561.method_43470("Sodium").method_54663(2616210),\n class_2561.method_43470(", the powerful and open rendering optimization mod for Minecraft.")\n }\n ),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("Mods like these are complex. They require "),\n class_2561.method_43470("thousands of hours").method_54663(16739840),\n class_2561.method_43470(" of development, debugging, and tuning to create the experience that players have come to expect.")\n }\n ),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("If you'd like to show your token of appreciation, and support the development of our mod in the process, then consider "),\n class_2561.method_43470("buying us a coffee").method_54663(15550926),\n class_2561.method_43470(".")\n }\n ),\n class_5348.method_29433(new class_5348[]{class_2561.method_43470("And thanks again for using our mod! We hope it helps you (and your computer.)")})\n );\n\n private SodiumOptionsGUI(class_437 prevScreen) {\n super(class_2561.method_43470("Sodium Renderer Settings"));\n this.prevScreen = prevScreen;\n this.pages.add(SodiumGameOptionPages.general());\n this.pages.add(SodiumGameOptionPages.quality());\n this.pages.add(SodiumGameOptionPages.performance());\n this.pages.add(SodiumGameOptionPages.advanced());\n this.checkPromptTimers();\n }\n\n private void checkPromptTimers() {\n if (!PlatformRuntimeInformation.getInstance().isDevelopmentEnvironment()) {\n SodiumGameOptions options = SodiumClientMod.options();\n if (!options.notifications.hasSeenDonationPrompt) {\n HashedFingerprint fingerprint = null;\n\n try {\n fingerprint = HashedFingerprint.loadFromDisk();\n } catch (Throwable var5) {\n SodiumClientMod.logger().error("Failed to read the fingerprint from disk", var5);\n }\n\n if (fingerprint != null) {\n Instant now = Instant.now();\n Instant threshold = Instant.ofEpochSecond(fingerprint.timestamp()).plus(3L, ChronoUnit.DAYS);\n if (now.isAfter(threshold)) {\n this.openDonationPrompt(options);\n }\n }\n }\n }\n }\n\n private void openDonationPrompt(SodiumGameOptions options) {\n ScreenPrompt prompt = new ScreenPrompt(\n this, DONATION_PROMPT_MESSAGE, 320, 190, new ScreenPrompt.Action(class_2561.method_43470("Buy us a coffee"), this::openDonationPage)\n );\n prompt.method_25365(true);\n options.notifications.hasSeenDonationPrompt = true;\n\n try {\n SodiumGameOptions.writeToDisk(options);\n } catch (IOException var4) {\n SodiumClientMod.logger().error("Failed to update config file", var4);\n }\n }\n\n public static class_437 createScreen(class_437 currentScreen) {\n return (class_437)(SodiumClientMod.options().isReadOnly()\n ? new ConfigCorruptedScreen(currentScreen, SodiumOptionsGUI::new)\n : new SodiumOptionsGUI(currentScreen));\n }\n\n public void setPage(OptionPage page) {\n this.currentPage = page;\n this.rebuildGUI();\n }\n\n protected void method_25426() {\n super.method_25426();\n this.rebuildGUI();\n if (this.prompt != null) {\n this.prompt.init();\n }\n }\n\n private void rebuildGUI() {\n this.controls.clear();\n this.method_37067();\n if (this.currentPage == null) {\n if (this.pages.isEmpty()) {\n throw new IllegalStateException("No pages are available?!");\n }\n\n this.currentPage = (OptionPage)this.pages.get(0);\n }\n\n this.rebuildGUIPages();\n this.rebuildGUIOptions();\n this.undoButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 211, this.field_22790 - 30, 65, 20), class_2561.method_43471("sodium.options.buttons.undo"), this::undoChanges\n );\n this.applyButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 142, this.field_22790 - 30, 65, 20), class_2561.method_43471("sodium.options.buttons.apply"), this::applyChanges\n );\n this.closeButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 73, this.field_22790 - 30, 65, 20), class_2561.method_43471("gui.done"), this::method_25419\n );\n this.donateButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 128, 6, 100, 20), class_2561.method_43471("sodium.options.buttons.donate"), this::openDonationPage\n );\n this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.field_22789 - 26, 6, 20, 20), class_2561.method_43470("x"), this::hideDonationButton);\n if (SodiumClientMod.options().notifications.hasClearedDonationButton) {\n this.setDonationButtonVisibility(false);\n }\n\n this.method_37063(this.undoButton);\n this.method_37063(this.applyButton);\n this.method_37063(this.closeButton);\n this.method_37063(this.donateButton);\n this.method_37063(this.hideDonateButton);\n }\n\n private void setDonationButtonVisibility(boolean value) {\n this.donateButton.setVisible(value);\n this.hideDonateButton.setVisible(value);\n }\n\n private void hideDonationButton() {\n SodiumGameOptions options = SodiumClientMod.options();\n options.notifications.hasClearedDonationButton = true;\n\n try {\n SodiumGameOptions.writeToDisk(options);\n } catch (IOException var3) {\n throw new RuntimeException("Failed to save configuration", var3);\n }\n\n this.setDonationButtonVisibility(false);\n }\n\n private void rebuildGUIPages() {\n int x = 6;\n int y = 6;\n\n for (OptionPage page : this.pages) {\n int width = 12 + this.field_22793.method_27525(page.getName());\n FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getName(), () -> this.setPage(page));\n button.setSelected(this.currentPage == page);\n x += width + 6;\n this.method_37063(button);\n }\n }\n\n private void rebuildGUIOptions() {\n int x = 6;\n int y = 28;\n\n for (UnmodifiableIterator var3 = this.currentPage.getGroups().iterator(); var3.hasNext(); y += 4) {\n OptionGroup group = (OptionGroup)var3.next();\n\n for (UnmodifiableIterator var5 = group.getOptions().iterator(); var5.hasNext(); y += 18) {\n Option option = (Option)var5.next();\n Control control = option.getControl();\n ControlElement element = control.createElement(new Dim2i(x, y, 240, 18));\n this.method_37063(element);\n this.controls.add(element);\n }\n }\n }\n\n public void method_25394(class_332 graphics, int mouseX, int mouseY, float delta) {\n this.updateControls();\n super.method_25394(graphics, this.prompt != null ? -1 : mouseX, this.prompt != null ? -1 : mouseY, delta);\n if (this.hoveredElement != null) {\n this.renderOptionTooltip(graphics, this.hoveredElement);\n }\n\n if (this.prompt != null) {\n this.prompt.method_25394(graphics, mouseX, mouseY, delta);\n }\n }\n\n private void updateControls() {\n ControlElement hovered = (ControlElement)this.getActiveControls()\n .filter(AbstractWidget::isHovered)\n .findFirst()\n .orElse((ControlElement)this.getActiveControls().filter(AbstractWidget::method_25370).findFirst().orElse(null));\n boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged);\n\n for (OptionPage page : this.pages) {\n UnmodifiableIterator var5 = page.getOptions().iterator();\n\n while (var5.hasNext()) {\n Option option = (Option)var5.next();\n if (option.hasChanged()) {\n hasChanges = true;\n }\n }\n }\n\n this.applyButton.setEnabled(hasChanges);\n this.undoButton.setVisible(hasChanges);\n this.closeButton.setEnabled(!hasChanges);\n this.hasPendingChanges = hasChanges;\n this.hoveredElement = hovered;\n }\n\n private Stream> getAllOptions() {\n return this.pages.stream().flatMap(s -> s.getOptions().stream());\n }\n\n private Stream> getActiveControls() {\n return this.controls.stream();\n }\n\n private void renderOptionTooltip(class_332 graphics, ControlElement element) {\n Dim2i dim = element.getDimensions();\n int textPadding = 3;\n int boxPadding = 3;\n int boxY = dim.y();\n int boxX = dim.getLimitX() + boxPadding;\n int boxWidth = Math.min(200, this.field_22789 - boxX - boxPadding);\n Option option = element.getOption();\n int splitWidth = boxWidth - textPadding * 2;\n List tooltip = new ArrayList(this.field_22793.method_1728(option.getTooltip(), splitWidth));\n OptionImpact impact = option.getImpact();\n if (impact != null) {\n class_5250 impactText = class_2561.method_43469("sodium.options.performance_impact_string", new Object[]{impact.getLocalizedName()});\n tooltip.addAll(this.field_22793.method_1728(impactText.method_27692(class_124.field_1080), splitWidth));\n }\n\n int boxHeight = tooltip.size() * 12 + boxPadding;\n int boxYLimit = boxY + boxHeight;\n int boxYCutoff = this.field_22790 - 40;\n if (boxYLimit > boxYCutoff) {\n boxY -= boxYLimit - boxYCutoff;\n }\n\n graphics.method_25296(boxX, boxY, boxX + boxWidth, boxY + boxHeight, -536870912, -536870912);\n\n for (int i = 0; i < tooltip.size(); i++) {\n graphics.method_35720(this.field_22793, (class_5481)tooltip.get(i), boxX + textPadding, boxY + textPadding + i * 12, -1);\n }\n }\n\n private void applyChanges() {\n HashSet> dirtyStorages = new HashSet();\n EnumSet flags = EnumSet.noneOf(OptionFlag.class);\n this.getAllOptions().forEach(option -> {\n if (option.hasChanged()) {\n option.applyChanges();\n flags.addAll(option.getFlags());\n dirtyStorages.add(option.getStorage());\n }\n });\n class_310 client = class_310.method_1551();\n if (client.field_1687 != null) {\n if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) {\n client.field_1769.method_3279();\n } else if (flags.contains(OptionFlag.REQUIRES_RENDERER_UPDATE)) {\n client.field_1769.method_3292();\n }\n }\n\n if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) {\n client.method_24041((Integer)client.field_1690.method_42563().method_41753());\n client.method_1513();\n }\n\n if (flags.contains(OptionFlag.REQUIRES_VIDEOMODE_RELOAD)) {\n client.method_22683().method_4475();\n }\n\n if (flags.contains(OptionFlag.REQUIRES_GAME_RESTART)) {\n Console.instance().logMessage(MessageLevel.WARN, "sodium.console.game_restart", true, 10.0);\n }\n\n for (OptionStorage storage : dirtyStorages) {\n storage.save();\n }\n }\n\n private void undoChanges() {\n this.getAllOptions().forEach(Option::reset);\n }\n\n private void openDonationPage() {\n class_156.method_668().method_670("https://caffeinemc.net/donate");\n }\n\n public boolean method_25404(int keyCode, int scanCode, int modifiers) {\n if (this.prompt != null && this.prompt.method_25404(keyCode, scanCode, modifiers)) {\n return true;\n } else if (this.prompt == null && keyCode == 80 && (modifiers & 1) != 0) {\n class_310.method_1551().method_1507(new class_446(this.prevScreen, class_310.method_1551(), class_310.method_1551().field_1690));\n return true;\n } else {\n return super.method_25404(keyCode, scanCode, modifiers);\n }\n }\n\n public boolean method_25402(double mouseX, double mouseY, int button) {\n if (this.prompt != null) {\n return this.prompt.method_25402(mouseX, mouseY, button);\n } else {\n boolean clicked = super.method_25402(mouseX, mouseY, button);\n if (!clicked) {\n this.method_25395(null);\n return true;\n } else {\n return clicked;\n }\n }\n }\n\n public boolean method_25422() {\n return !this.hasPendingChanges;\n }\n\n public void method_25419() {\n this.field_22787.method_1507(this.prevScreen);\n }\n\n public List method_25396() {\n return this.prompt == null ? super.method_25396() : this.prompt.getWidgets();\n }\n\n @Override\n public void setPrompt(@Nullable ScreenPrompt prompt) {\n this.prompt = prompt;\n }\n\n @Nullable\n @Override\n public ScreenPrompt getPrompt() {\n return this.prompt;\n }\n\n @Override\n public Dim2i getDimensions() {\n return new Dim2i(0, 0, this.field_22789, this.field_22790);\n }\n}\n {"url": "https://caffeinemc.net/donate"} low -5 2 2048cee1aed753e10480183673ffb5e685de2ce414e99e93f7d1dd11a87a19af net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks package net.caffeinemc.mods.sodium.client.compatibility.checks;\n\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper;\nimport org.lwjgl.Version;\n\npublic class PreLaunchChecks {\n private static final String REQUIRED_LWJGL_VERSION = "3.3.3";\n\n public static void checkEnvironment() {\n if (BugChecks.ISSUE_2561) {\n checkLwjglRuntimeVersion();\n }\n }\n\n private static void checkLwjglRuntimeVersion() {\n if (!isUsingKnownCompatibleLwjglVersion()) {\n String advice;\n if (isUsingPrismLauncher()) {\n advice = "It appears you are using Prism Launcher to start the game. You can likely fix this problem by opening your instance settings and navigating to the Versionsection in the sidebar.";\n } else {\n advice = "You must change the LWJGL version in your launcher to continue. This is usually controlled by the settings for a profile or instance in your launcher.";\n }\n\n String message = "The game failed to start because the currently active LWJGL version is not compatible.\\n\\nInstalled version: ###CURRENT_VERSION###\\nRequired version: ###REQUIRED_VERSION###\\n\\n###ADVICE_STRING###"\n .replace("###CURRENT_VERSION###", Version.getVersion())\n .replace("###REQUIRED_VERSION###", "3.3.3")\n .replace("###ADVICE_STRING###", advice);\n PlatformHelper.showCriticalErrorAndClose(\n null, "Sodium Renderer - Unsupported LWJGL", message, "https://link.caffeinemc.net/help/sodium/runtime-issue/lwjgl3/gh-2561"\n );\n }\n }\n\n private static boolean isUsingKnownCompatibleLwjglVersion() {\n return Version.getVersion().startsWith("3.3.3");\n }\n\n private static boolean isUsingPrismLauncher() {\n return getLauncherBrand().equalsIgnoreCase("PrismLauncher");\n }\n\n private static String getLauncherBrand() {\n return System.getProperty("minecraft.launcher.brand", "unknown");\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/runtime-issue/lwjgl3/gh-2561"} low -6 2 0b9d53bc482f11c0d8c71a9689645132f0a50249838091b3e6f95fefbc279075 net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner package net.caffeinemc.mods.sodium.client.compatibility.checks;\n\nimport com.sun.jna.Platform;\nimport com.sun.jna.platform.win32.Kernel32;\nimport com.sun.jna.platform.win32.Kernel32Util;\nimport com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport net.caffeinemc.mods.sodium.client.platform.MessageBox;\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle;\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.Version;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionInfo;\nimport org.jetbrains.annotations.Nullable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ModuleScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-Win32ModuleChecks");\n private static final String[] RTSS_HOOKS_MODULE_NAMES = new String[]{"RTSSHooks64.dll", "RTSSHooks.dll"};\n private static final String[] ASUS_GPU_TWEAK_MODULE_NAMES = new String[]{\n "GTIII-OSD64-GL.dll", "GTIII-OSD-GL.dll", "GTIII-OSD64-VK.dll", "GTIII-OSD-VK.dll", "GTIII-OSD64.dll", "GTIII-OSD.dll"\n };\n\n public static void checkModules(NativeWindowHandle window) {\n List modules;\n try {\n modules = listModules();\n } catch (Throwable var3) {\n LOGGER.warn("Failed to scan the currently loaded modules", var3);\n return;\n }\n\n if (!modules.isEmpty()) {\n if (BugChecks.ISSUE_2048 && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {\n checkRTSSModules(window);\n }\n\n if (BugChecks.ISSUE_2637 && isModuleLoaded(modules, ASUS_GPU_TWEAK_MODULE_NAMES)) {\n checkASUSGpuTweakIII(window);\n }\n }\n }\n\n private static List listModules() {\n if (!Platform.isWindows()) {\n return List.of();\n } else {\n int pid = Kernel32.INSTANCE.GetCurrentProcessId();\n ArrayList modules = new ArrayList();\n\n for (MODULEENTRY32W module : Kernel32Util.getModules(pid)) {\n modules.add(module.szModule());\n }\n\n return Collections.unmodifiableList(modules);\n }\n }\n\n private static void checkRTSSModules(NativeWindowHandle window) {\n LOGGER.warn("RivaTuner Statistics Server (RTSS) has injected into the process! Attempting to apply workarounds for compatibility...");\n WindowsFileVersion version = null;\n\n try {\n version = findRTSSModuleVersion();\n } catch (Throwable var3) {\n LOGGER.warn("Exception thrown while reading file version", var3);\n }\n\n if (version == null) {\n LOGGER.warn("Could not determine version of RivaTuner Statistics Server");\n } else {\n LOGGER.info("Detected RivaTuner Statistics Server version: {}", version);\n }\n\n if (version == null || !isRTSSCompatible(version)) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium.\\n\\nYou must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n );\n throw new RuntimeException(\n "The installed version of RivaTuner Statistics Server (RTSS) is not compatible with Sodium, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n );\n }\n }\n\n private static boolean isRTSSCompatible(WindowsFileVersion version) {\n int x = version.x();\n int y = version.y();\n int z = version.z();\n return x > 7 || x == 7 && y > 3 || x == 7 && y == 3 && z >= 4;\n }\n\n private static void checkASUSGpuTweakIII(NativeWindowHandle window) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "ASUS GPU Tweak III is not compatible with Minecraft, and causes extreme performance issues and severe graphical corruption when used with Minecraft.\\n\\nYou *must* do one of the following things to continue:\\n\\na) Open the settings of ASUS GPU Tweak III, enable the Blacklist option, click \\"Browse from file...\\", and select the Java runtime (javaw.exe) which is used by Minecraft.\\n\\nb) Completely uninstall the ASUS GPU Tweak III application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n );\n throw new RuntimeException(\n "ASUS GPU Tweak III is not compatible with Minecraft, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n );\n }\n\n @Nullable\n private static WindowsFileVersion findRTSSModuleVersion() {\n long module;\n try {\n module = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleHandleByNames(RTSS_HOOKS_MODULE_NAMES);\n } catch (Throwable var9) {\n LOGGER.warn("Failed to locate module", var9);\n return null;\n }\n\n String moduleFileName;\n try {\n moduleFileName = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleFileName(module);\n } catch (Throwable var8) {\n LOGGER.warn("Failed to get path of module", var8);\n return null;\n }\n\n Path modulePath = Path.of(moduleFileName);\n Path moduleDirectory = modulePath.getParent();\n LOGGER.info("Searching directory: {}", moduleDirectory);\n Path executablePath = moduleDirectory.resolve("RTSS.exe");\n if (!Files.exists(executablePath, new LinkOption[0])) {\n LOGGER.warn("Could not find executable: {}", executablePath);\n return null;\n } else {\n LOGGER.info("Parsing file: {}", executablePath);\n VersionInfo version = Version.getModuleFileVersion(executablePath.toAbsolutePath().toString());\n if (version == null) {\n LOGGER.warn("Couldn't find version structure");\n return null;\n } else {\n VersionFixedFileInfoStruct fileVersion = version.queryFixedFileInfo();\n if (fileVersion == null) {\n LOGGER.warn("Couldn't query file version");\n return null;\n } else {\n return WindowsFileVersion.fromFileVersion(fileVersion);\n }\n }\n }\n }\n\n private static boolean isModuleLoaded(List modules, String[] names) {\n for (String name : names) {\n for (String module : modules) {\n if (module.equalsIgnoreCase(name)) {\n return true;\n }\n }\n }\n\n return false;\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"} low -7 2 c7ef03b142e9371c5b10fd54ee7a22060872bd3addb96c6fa21ab10ccdc4b481 net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner package net.caffeinemc.mods.sodium.client.compatibility.checks;\n\nimport com.sun.jna.Platform;\nimport com.sun.jna.platform.win32.Kernel32;\nimport com.sun.jna.platform.win32.Kernel32Util;\nimport com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport net.caffeinemc.mods.sodium.client.platform.MessageBox;\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle;\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.Version;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct;\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionInfo;\nimport org.jetbrains.annotations.Nullable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ModuleScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-Win32ModuleChecks");\n private static final String[] RTSS_HOOKS_MODULE_NAMES = new String[]{"RTSSHooks64.dll", "RTSSHooks.dll"};\n private static final String[] ASUS_GPU_TWEAK_MODULE_NAMES = new String[]{\n "GTIII-OSD64-GL.dll", "GTIII-OSD-GL.dll", "GTIII-OSD64-VK.dll", "GTIII-OSD-VK.dll", "GTIII-OSD64.dll", "GTIII-OSD.dll"\n };\n\n public static void checkModules(NativeWindowHandle window) {\n List modules;\n try {\n modules = listModules();\n } catch (Throwable var3) {\n LOGGER.warn("Failed to scan the currently loaded modules", var3);\n return;\n }\n\n if (!modules.isEmpty()) {\n if (BugChecks.ISSUE_2048 && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {\n checkRTSSModules(window);\n }\n\n if (BugChecks.ISSUE_2637 && isModuleLoaded(modules, ASUS_GPU_TWEAK_MODULE_NAMES)) {\n checkASUSGpuTweakIII(window);\n }\n }\n }\n\n private static List listModules() {\n if (!Platform.isWindows()) {\n return List.of();\n } else {\n int pid = Kernel32.INSTANCE.GetCurrentProcessId();\n ArrayList modules = new ArrayList();\n\n for (MODULEENTRY32W module : Kernel32Util.getModules(pid)) {\n modules.add(module.szModule());\n }\n\n return Collections.unmodifiableList(modules);\n }\n }\n\n private static void checkRTSSModules(NativeWindowHandle window) {\n LOGGER.warn("RivaTuner Statistics Server (RTSS) has injected into the process! Attempting to apply workarounds for compatibility...");\n WindowsFileVersion version = null;\n\n try {\n version = findRTSSModuleVersion();\n } catch (Throwable var3) {\n LOGGER.warn("Exception thrown while reading file version", var3);\n }\n\n if (version == null) {\n LOGGER.warn("Could not determine version of RivaTuner Statistics Server");\n } else {\n LOGGER.info("Detected RivaTuner Statistics Server version: {}", version);\n }\n\n if (version == null || !isRTSSCompatible(version)) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium.\\n\\nYou must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n );\n throw new RuntimeException(\n "The installed version of RivaTuner Statistics Server (RTSS) is not compatible with Sodium, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n );\n }\n }\n\n private static boolean isRTSSCompatible(WindowsFileVersion version) {\n int x = version.x();\n int y = version.y();\n int z = version.z();\n return x > 7 || x == 7 && y > 3 || x == 7 && y == 3 && z >= 4;\n }\n\n private static void checkASUSGpuTweakIII(NativeWindowHandle window) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "ASUS GPU Tweak III is not compatible with Minecraft, and causes extreme performance issues and severe graphical corruption when used with Minecraft.\\n\\nYou *must* do one of the following things to continue:\\n\\na) Open the settings of ASUS GPU Tweak III, enable the Blacklist option, click \\"Browse from file...\\", and select the Java runtime (javaw.exe) which is used by Minecraft.\\n\\nb) Completely uninstall the ASUS GPU Tweak III application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n );\n throw new RuntimeException(\n "ASUS GPU Tweak III is not compatible with Minecraft, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n );\n }\n\n @Nullable\n private static WindowsFileVersion findRTSSModuleVersion() {\n long module;\n try {\n module = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleHandleByNames(RTSS_HOOKS_MODULE_NAMES);\n } catch (Throwable var9) {\n LOGGER.warn("Failed to locate module", var9);\n return null;\n }\n\n String moduleFileName;\n try {\n moduleFileName = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleFileName(module);\n } catch (Throwable var8) {\n LOGGER.warn("Failed to get path of module", var8);\n return null;\n }\n\n Path modulePath = Path.of(moduleFileName);\n Path moduleDirectory = modulePath.getParent();\n LOGGER.info("Searching directory: {}", moduleDirectory);\n Path executablePath = moduleDirectory.resolve("RTSS.exe");\n if (!Files.exists(executablePath, new LinkOption[0])) {\n LOGGER.warn("Could not find executable: {}", executablePath);\n return null;\n } else {\n LOGGER.info("Parsing file: {}", executablePath);\n VersionInfo version = Version.getModuleFileVersion(executablePath.toAbsolutePath().toString());\n if (version == null) {\n LOGGER.warn("Couldn't find version structure");\n return null;\n } else {\n VersionFixedFileInfoStruct fileVersion = version.queryFixedFileInfo();\n if (fileVersion == null) {\n LOGGER.warn("Couldn't query file version");\n return null;\n } else {\n return WindowsFileVersion.fromFileVersion(fileVersion);\n }\n }\n }\n }\n\n private static boolean isModuleLoaded(List modules, String[] names) {\n for (String name : names) {\n for (String module : modules) {\n if (module.equalsIgnoreCase(name)) {\n return true;\n }\n }\n }\n\n return false;\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"} low -8 2 54aa6d079497c9fc459f84c660a303496d18fa17c35c0e22cbe2160924de212e net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks package net.caffeinemc.mods.sodium.client.compatibility.checks;\n\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo;\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds;\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle;\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper;\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion;\n\nclass GraphicsDriverChecks {\n static void postContextInit(NativeWindowHandle window, GlContextInfo context) {\n GraphicsAdapterVendor vendor = GraphicsAdapterVendor.fromContext(context);\n if (vendor != GraphicsAdapterVendor.UNKNOWN) {\n if (vendor == GraphicsAdapterVendor.INTEL && BugChecks.ISSUE_899) {\n WindowsFileVersion installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899();\n if (installedVersion != null) {\n String installedVersionString = installedVersion.toString();\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed Intel Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 10.18.10.5161 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"\n );\n }\n }\n\n if (vendor == GraphicsAdapterVendor.NVIDIA && BugChecks.ISSUE_1486) {\n WindowsFileVersion installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486();\n if (installedVersion != null) {\n String installedVersionString = NvidiaDriverVersion.parse(installedVersion).toString();\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed NVIDIA Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 536.23 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"\n );\n }\n }\n }\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"} low -9 2 5ff865ff6c2e250096fb15b9a943c645deb8558eddc72fa1b492748eb2c78b32 net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks package net.caffeinemc.mods.sodium.client.compatibility.checks;\n\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo;\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion;\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds;\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle;\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper;\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion;\n\nclass GraphicsDriverChecks {\n static void postContextInit(NativeWindowHandle window, GlContextInfo context) {\n GraphicsAdapterVendor vendor = GraphicsAdapterVendor.fromContext(context);\n if (vendor != GraphicsAdapterVendor.UNKNOWN) {\n if (vendor == GraphicsAdapterVendor.INTEL && BugChecks.ISSUE_899) {\n WindowsFileVersion installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899();\n if (installedVersion != null) {\n String installedVersionString = installedVersion.toString();\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed Intel Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 10.18.10.5161 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"\n );\n }\n }\n\n if (vendor == GraphicsAdapterVendor.NVIDIA && BugChecks.ISSUE_1486) {\n WindowsFileVersion installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486();\n if (installedVersion != null) {\n String installedVersionString = NvidiaDriverVersion.parse(installedVersion).toString();\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed NVIDIA Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 536.23 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"\n );\n }\n }\n }\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"} low -10 2 dcf24bb91e7861b7a382958053c3efc201684e93df7ce058e849effa3f947fb0 net/caffeinemc/mods/sodium/client/checks/ResourcePackScanner package net.caffeinemc.mods.sodium.client.checks;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport net.caffeinemc.mods.sodium.client.console.Console;\nimport net.caffeinemc.mods.sodium.client.console.message.MessageLevel;\nimport net.minecraft.class_3258;\nimport net.minecraft.class_3259;\nimport net.minecraft.class_3262;\nimport net.minecraft.class_3264;\nimport net.minecraft.class_3300;\nimport org.jetbrains.annotations.NotNull;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ResourcePackScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-ResourcePackScanner");\n private static final Set SHADER_PROGRAM_BLACKLIST = Set.of(\n "rendertype_solid.vsh",\n "rendertype_solid.fsh",\n "rendertype_solid.json",\n "rendertype_cutout_mipped.vsh",\n "rendertype_cutout_mipped.fsh",\n "rendertype_cutout_mipped.json",\n "rendertype_cutout.vsh",\n "rendertype_cutout.fsh",\n "rendertype_cutout.json",\n "rendertype_translucent.vsh",\n "rendertype_translucent.fsh",\n "rendertype_translucent.json",\n "rendertype_tripwire.vsh",\n "rendertype_tripwire.fsh",\n "rendertype_tripwire.json",\n "rendertype_clouds.vsh",\n "rendertype_clouds.fsh",\n "rendertype_clouds.json"\n );\n private static final Set SHADER_INCLUDE_BLACKLIST = Set.of("light.glsl", "fog.glsl");\n\n public static void checkIfCoreShaderLoaded(class_3300 manager) {\n List outputs = manager.method_29213()\n .filter(ResourcePackScanner::isExternalResourcePack)\n .map(ResourcePackScanner::scanResources)\n .toList();\n printToasts(outputs);\n printCompatibilityReport(outputs);\n }\n\n private static void printToasts(Collection resourcePacks) {\n List incompatibleResourcePacks = resourcePacks.stream().filter(pack -> !pack.shaderPrograms.isEmpty()).toList();\n List likelyIncompatibleResourcePacks = resourcePacks.stream()\n .filter(pack -> !pack.shaderIncludes.isEmpty())\n .filter(pack -> !incompatibleResourcePacks.contains(pack))\n .toList();\n boolean shown = false;\n if (!incompatibleResourcePacks.isEmpty()) {\n showConsoleMessage("sodium.console.core_shaders_error", true, MessageLevel.SEVERE);\n\n for (ResourcePackScanner.ScannedResourcePack entry : incompatibleResourcePacks) {\n showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.SEVERE);\n }\n\n shown = true;\n }\n\n if (!likelyIncompatibleResourcePacks.isEmpty()) {\n showConsoleMessage("sodium.console.core_shaders_warn", true, MessageLevel.WARN);\n\n for (ResourcePackScanner.ScannedResourcePack entry : likelyIncompatibleResourcePacks) {\n showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.WARN);\n }\n\n shown = true;\n }\n\n if (shown) {\n showConsoleMessage("sodium.console.core_shaders_info", true, MessageLevel.INFO);\n }\n }\n\n private static void printCompatibilityReport(Collection scanResults) {\n StringBuilder builder = new StringBuilder();\n\n for (ResourcePackScanner.ScannedResourcePack entry : scanResults) {\n if (!entry.shaderPrograms.isEmpty() || !entry.shaderIncludes.isEmpty()) {\n builder.append("- Resource pack: ").append(getResourcePackName(entry.resourcePack)).append("\\n");\n if (!entry.shaderPrograms.isEmpty()) {\n emitProblem(\n builder,\n "The resource pack replaces terrain shaders, which are not supported",\n "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs",\n entry.shaderPrograms\n );\n }\n\n if (!entry.shaderIncludes.isEmpty()) {\n emitProblem(\n builder,\n "The resource pack modifies shader include files, which are not fully supported",\n "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs",\n entry.shaderIncludes\n );\n }\n }\n }\n\n if (!builder.isEmpty()) {\n LOGGER.error("The following compatibility issues were found with installed resource packs:\\n{}", builder);\n }\n }\n\n private static void emitProblem(StringBuilder builder, String description, String url, List resources) {\n builder.append("\\t- Problem found: ").append("\\n");\n builder.append("\\t\\t- Description:\\n\\t\\t\\t").append(description).append("\\n");\n builder.append("\\t\\t- More information: ").append(url).append("\\n");\n builder.append("\\t\\t- Files: ").append("\\n");\n\n for (String resource : resources) {\n builder.append("\\t\\t\\t- ").append(resource).append("\\n");\n }\n }\n\n @NotNull\n private static ResourcePackScanner.ScannedResourcePack scanResources(class_3262 resourcePack) {\n List ignoredShaders = determineIgnoredShaders(resourcePack);\n if (!ignoredShaders.isEmpty()) {\n LOGGER.warn(\n "Resource pack '{}' indicates the following shaders should be ignored: {}", getResourcePackName(resourcePack), String.join(", ", ignoredShaders)\n );\n }\n\n ArrayList unsupportedShaderPrograms = new ArrayList();\n ArrayList unsupportedShaderIncludes = new ArrayList();\n resourcePack.method_14408(class_3264.field_14188, "minecraft", "shaders", (identifier, supplier) -> {\n String path = identifier.method_12832();\n String name = path.substring(path.lastIndexOf(47) + 1);\n if (!ignoredShaders.contains(name)) {\n if (SHADER_PROGRAM_BLACKLIST.contains(name)) {\n unsupportedShaderPrograms.add(path);\n } else if (SHADER_INCLUDE_BLACKLIST.contains(name)) {\n unsupportedShaderIncludes.add(path);\n }\n }\n });\n return new ResourcePackScanner.ScannedResourcePack(resourcePack, unsupportedShaderPrograms, unsupportedShaderIncludes);\n }\n\n private static boolean isExternalResourcePack(class_3262 pack) {\n return pack instanceof class_3259 || pack instanceof class_3258;\n }\n\n private static String getResourcePackName(class_3262 pack) {\n String path = pack.method_14409();\n return path.startsWith("file/") ? path.substring(5) : path;\n }\n\n private static List determineIgnoredShaders(class_3262 resourcePack) {\n ArrayList ignoredShaders = new ArrayList();\n\n try {\n SodiumResourcePackMetadata meta = (SodiumResourcePackMetadata)resourcePack.method_14407(SodiumResourcePackMetadata.SERIALIZER);\n if (meta != null) {\n ignoredShaders.addAll(meta.ignoredShaders());\n }\n } catch (IOException var3) {\n LOGGER.error("Failed to load pack.mcmeta file for resource pack '{}'", resourcePack.method_14409());\n }\n\n return ignoredShaders;\n }\n\n private static void showConsoleMessage(String message, boolean translatable, MessageLevel messageLevel) {\n Console.instance().logMessage(messageLevel, message, translatable, 12.5);\n }\n\n private record ScannedResourcePack(class_3262 resourcePack, ArrayList shaderPrograms, ArrayList shaderIncludes) {\n }\n}\n {"url": "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs"} low +1 1 d670186a0e5210fc2b9332a2163849740f19bec59a99d890bef0ae9e6608f83d net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl package net.caffeinemc.mods.sodium.desktop.utils.browse; +\n\nimport java.io.IOException; +\nimport java.util.Locale; +\n\nclass XDGImpl implements BrowseUrlHandler {\n public static boolean isSupported() {\n String os = System.getProperty("os.name").toLowerCase(Locale.ROOT); +\n return os.equals("linux"); +\n }\n\n @Override\n public void browseTo(String url) throws IOException {\n Process process = Runtime.getRuntime().exec(new String[]{"xdg-open", url}); +\n\n try {\n int result = process.waitFor(); +\n if (result != 0) {\n throw new IOException("xdg-open exited with code: %d".formatted(result)); +\n }\n } catch (InterruptedException var4) {\n throw new RuntimeException(var4); +\n }\n }\n}\n {} medium +2 1 317dd815f60f04f1cef5d855e30f6a2719570c583ef49ae94ca2b563179fc1fa net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe package net.caffeinemc.mods.sodium.client.compatibility.environment.probe; +\n\nimport java.io.BufferedReader; +\nimport java.io.IOException; +\nimport java.io.InputStreamReader; +\nimport java.nio.file.Files; +\nimport java.nio.file.Path; +\nimport java.util.ArrayList; +\nimport java.util.Collection; +\nimport java.util.Collections; +\nimport java.util.List; +\nimport java.util.Set; +\nimport java.util.stream.Stream; +\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.OsUtils; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMT; +\nimport org.jetbrains.annotations.Nullable; +\nimport org.slf4j.Logger; +\nimport org.slf4j.LoggerFactory; +\n\npublic class GraphicsAdapterProbe {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-GraphicsAdapterProbe"); +\n private static final Set LINUX_PCI_CLASSES = Set.of("0x030000", "0x030001", "0x030200", "0x038000"); +\n private static List ADAPTERS = List.of(); +\n\n public static void findAdapters() {\n LOGGER.info("Searching for graphics cards..."); +\n\n List adapters; +\n try {\n adapters = switch (OsUtils.getOs()) {\n case WIN -> findAdapters$Windows(); +\n case LINUX -> findAdapters$Linux(); +\n default -> null; +\n }; +\n } catch (Exception var3) {\n LOGGER.error("Failed to find graphics adapters!", var3); +\n return; +\n }\n\n if (adapters != null) {\n if (adapters.isEmpty()) {\n LOGGER.warn(\n "Could not find any graphics adapters! Probably the device is not on a bus we can probe, or there are no devices supporting 3D acceleration."\n ); +\n } else {\n for (GraphicsAdapterInfo adapter : adapters) {\n LOGGER.info("Found graphics adapter: {}", adapter); +\n }\n }\n\n ADAPTERS = adapters; +\n }\n }\n\n private static List findAdapters$Windows() {\n return D3DKMT.findGraphicsAdapters(); +\n }\n\n private static List findAdapters$Linux() {\n ArrayList results = new ArrayList(); +\n\n try {\n Stream devices = Files.list(Path.of("/sys/bus/pci/devices/")); +\n\n try {\n for (Path devicePath : devices::iterator) {\n String deviceClass = Files.readString(devicePath.resolve("class")).trim(); +\n if (LINUX_PCI_CLASSES.contains(deviceClass)) {\n String pciVendorId = Files.readString(devicePath.resolve("vendor")).trim(); +\n String pciDeviceId = Files.readString(devicePath.resolve("device")).trim(); +\n GraphicsAdapterVendor adapterVendor = GraphicsAdapterVendor.fromPciVendorId(pciVendorId); +\n String adapterName = getPciDeviceName$Linux(pciVendorId, pciDeviceId); +\n if (adapterName == null) {\n adapterName = ""; +\n }\n\n GraphicsAdapterInfo.LinuxPciAdapterInfo info = new GraphicsAdapterInfo.LinuxPciAdapterInfo(\n adapterVendor, adapterName, pciVendorId, pciDeviceId\n ); +\n results.add(info); +\n }\n }\n } catch (Throwable var12) {\n if (devices != null) {\n try {\n devices.close(); +\n } catch (Throwable var11) {\n var12.addSuppressed(var11); +\n }\n }\n\n throw var12; +\n }\n\n if (devices != null) {\n devices.close(); +\n }\n } catch (IOException var13) {\n }\n\n return results; +\n }\n\n @Nullable\n private static String getPciDeviceName$Linux(String vendorId, String deviceId) {\n String deviceFilter = vendorId.substring(2) + ":" + deviceId.substring(2); +\n\n try {\n Process process = Runtime.getRuntime().exec(new String[]{"lspci", "-vmm", "-d", deviceFilter}); +\n int result = process.waitFor(); +\n if (result != 0) {\n throw new IOException("lspci exited with error code: %s".formatted(result)); +\n } else {\n BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); +\n\n String var7; +\n label40: {\n String line; +\n try {\n while ((line = reader.readLine()) != null) {\n if (line.startsWith("Device:")) {\n var7 = line.substring("Device:".length()).trim(); +\n break label40; +\n }\n }\n } catch (Throwable var9) {\n try {\n reader.close(); +\n } catch (Throwable var8) {\n var9.addSuppressed(var8); +\n }\n\n throw var9; +\n }\n\n reader.close(); +\n throw new IOException("lspci did not return a device name"); +\n }\n\n reader.close(); +\n return var7; +\n }\n } catch (Throwable var10) {\n LOGGER.warn("Failed to query PCI device name for %s:%s".formatted(vendorId, deviceId), var10); +\n return null; +\n }\n }\n\n public static Collection getAdapters() {\n if (ADAPTERS == null) {\n LOGGER.error("Graphics adapters not probed yet; +returning an empty list."); +\n return Collections.emptyList(); +\n } else {\n return ADAPTERS; +\n }\n }\n}\n {} medium +3 2 5ba58b7f9dcc59f14c8a0fd9b78c23a19723791bd9006ed408d43557ea24abb4 net/caffeinemc/mods/sodium/desktop/LaunchWarn package net.caffeinemc.mods.sodium.desktop; +\n\nimport java.awt.GraphicsEnvironment; +\nimport java.io.IOException; +\nimport javax.swing.JDialog; +\nimport javax.swing.JOptionPane; +\nimport javax.swing.UIManager; +\nimport javax.swing.UnsupportedLookAndFeelException; +\nimport net.caffeinemc.mods.sodium.desktop.utils.browse.BrowseUrlHandler; +\n\npublic class LaunchWarn {\n private static final String HELP_URL = "https://link.caffeinemc.net/guides/sodium/installation"; +\n private static final String RICH_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

"; +\n private static final String FALLBACK_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"; +\n private static final String FAILED_TO_BROWSE_MESSAGE = "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

"; +\n public static final String WINDOW_TITLE = "Sodium"; +\n\n public static void main(String[] args) {\n if (GraphicsEnvironment.isHeadless()) {\n showHeadlessError(); +\n } else {\n showGraphicalError(); +\n }\n }\n\n private static void showHeadlessError() {\n System.err\n .println(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"\n ); +\n }\n\n private static void showGraphicalError() {\n trySetSystemLookAndFeel(); +\n trySetSystemFontPreferences(); +\n BrowseUrlHandler browseUrlHandler = BrowseUrlHandler.createImplementation(); +\n if (browseUrlHandler != null) {\n showRichGraphicalDialog(browseUrlHandler); +\n } else {\n showFallbackGraphicalDialog(); +\n }\n\n System.exit(0); +\n }\n\n private static void showRichGraphicalDialog(BrowseUrlHandler browseUrlHandler) {\n int selectedOption = showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

",\n "Sodium",\n 0,\n 1,\n new String[]{"Help", "Close"},\n 0\n ); +\n if (selectedOption == 0) {\n log("Opening URL: https://link.caffeinemc.net/guides/sodium/installation"); +\n\n try {\n browseUrlHandler.browseTo("https://link.caffeinemc.net/guides/sodium/installation"); +\n } catch (IOException var3) {\n log("Failed to open default web browser!", var3); +\n showDialogBox(\n "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

",\n "Sodium",\n -1,\n 2,\n null,\n -1\n ); +\n }\n }\n }\n\n private static void showFallbackGraphicalDialog() {\n showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

",\n "Sodium",\n -1,\n 1,\n null,\n null\n ); +\n }\n\n private static int showDialogBox(String message, String title, int optionType, int messageType, String[] options, Object initialValue) {\n JOptionPane pane = new JOptionPane(message, messageType, optionType, null, options, initialValue); +\n JDialog dialog = pane.createDialog(title); +\n dialog.setVisible(true); +\n Object selectedValue = pane.getValue(); +\n if (selectedValue == null) {\n return -1; +\n } else if (options == null) {\n return selectedValue instanceof Integer ? (Integer)selectedValue : -1; +\n } else {\n for (int counter = 0; +counter < options.length; +counter++) {\n String option = options[counter]; +\n if (option.equals(selectedValue)) {\n return counter; +\n }\n }\n\n return -1; +\n }\n }\n\n private static void trySetSystemLookAndFeel() {\n try {\n UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); +\n } catch (UnsupportedLookAndFeelException | ReflectiveOperationException var1) {\n }\n }\n\n private static void trySetSystemFontPreferences() {\n System.setProperty("awt.useSystemAAFontSettings", "on"); +\n }\n\n private static void log(String message) {\n System.err.println(message); +\n }\n\n private static void log(String message, Throwable exception) {\n System.err.println(message); +\n exception.printStackTrace(System.err); +\n }\n}\n {"url": "https://link.caffeinemc.net/guides/sodium/installation"} low +4 2 34a4ceb119311f669d4b3b036dfef9f93c1e86f765582ebf556b92486766f861 net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI package net.caffeinemc.mods.sodium.client.gui; +\n\nimport com.google.common.collect.UnmodifiableIterator; +\nimport java.io.IOException; +\nimport java.time.Instant; +\nimport java.time.temporal.ChronoUnit; +\nimport java.util.ArrayList; +\nimport java.util.EnumSet; +\nimport java.util.HashSet; +\nimport java.util.List; +\nimport java.util.stream.Stream; +\nimport net.caffeinemc.mods.sodium.client.SodiumClientMod; +\nimport net.caffeinemc.mods.sodium.client.console.Console; +\nimport net.caffeinemc.mods.sodium.client.console.message.MessageLevel; +\nimport net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint; +\nimport net.caffeinemc.mods.sodium.client.gui.options.Option; +\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionFlag; +\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionGroup; +\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionImpact; +\nimport net.caffeinemc.mods.sodium.client.gui.options.OptionPage; +\nimport net.caffeinemc.mods.sodium.client.gui.options.control.Control; +\nimport net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement; +\nimport net.caffeinemc.mods.sodium.client.gui.options.storage.OptionStorage; +\nimport net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPrompt; +\nimport net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPromptable; +\nimport net.caffeinemc.mods.sodium.client.gui.screen.ConfigCorruptedScreen; +\nimport net.caffeinemc.mods.sodium.client.gui.widgets.AbstractWidget; +\nimport net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget; +\nimport net.caffeinemc.mods.sodium.client.services.PlatformRuntimeInformation; +\nimport net.caffeinemc.mods.sodium.client.util.Dim2i; +\nimport net.minecraft.class_124; +\nimport net.minecraft.class_156; +\nimport net.minecraft.class_2561; +\nimport net.minecraft.class_310; +\nimport net.minecraft.class_332; +\nimport net.minecraft.class_364; +\nimport net.minecraft.class_437; +\nimport net.minecraft.class_446; +\nimport net.minecraft.class_5250; +\nimport net.minecraft.class_5348; +\nimport net.minecraft.class_5481; +\nimport org.jetbrains.annotations.Nullable; +\n\npublic class SodiumOptionsGUI extends class_437 implements ScreenPromptable {\n private final List pages = new ArrayList(); +\n private final List> controls = new ArrayList(); +\n private final class_437 prevScreen; +\n private OptionPage currentPage; +\n private FlatButtonWidget applyButton; +\n private FlatButtonWidget closeButton; +\n private FlatButtonWidget undoButton; +\n private FlatButtonWidget donateButton; +\n private FlatButtonWidget hideDonateButton; +\n private boolean hasPendingChanges; +\n private ControlElement hoveredElement; +\n @Nullable\n private ScreenPrompt prompt; +\n private static final List DONATION_PROMPT_MESSAGE = List.of(\n class_5348.method_29433(new class_5348[]{class_2561.method_43470("Hello!")}),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("It seems that you've been enjoying "),\n class_2561.method_43470("Sodium").method_54663(2616210),\n class_2561.method_43470(", the powerful and open rendering optimization mod for Minecraft.")\n }\n ),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("Mods like these are complex. They require "),\n class_2561.method_43470("thousands of hours").method_54663(16739840),\n class_2561.method_43470(" of development, debugging, and tuning to create the experience that players have come to expect.")\n }\n ),\n class_5348.method_29433(\n new class_5348[]{\n class_2561.method_43470("If you'd like to show your token of appreciation, and support the development of our mod in the process, then consider "),\n class_2561.method_43470("buying us a coffee").method_54663(15550926),\n class_2561.method_43470(".")\n }\n ),\n class_5348.method_29433(new class_5348[]{class_2561.method_43470("And thanks again for using our mod! We hope it helps you (and your computer.)")})\n ); +\n\n private SodiumOptionsGUI(class_437 prevScreen) {\n super(class_2561.method_43470("Sodium Renderer Settings")); +\n this.prevScreen = prevScreen; +\n this.pages.add(SodiumGameOptionPages.general()); +\n this.pages.add(SodiumGameOptionPages.quality()); +\n this.pages.add(SodiumGameOptionPages.performance()); +\n this.pages.add(SodiumGameOptionPages.advanced()); +\n this.checkPromptTimers(); +\n }\n\n private void checkPromptTimers() {\n if (!PlatformRuntimeInformation.getInstance().isDevelopmentEnvironment()) {\n SodiumGameOptions options = SodiumClientMod.options(); +\n if (!options.notifications.hasSeenDonationPrompt) {\n HashedFingerprint fingerprint = null; +\n\n try {\n fingerprint = HashedFingerprint.loadFromDisk(); +\n } catch (Throwable var5) {\n SodiumClientMod.logger().error("Failed to read the fingerprint from disk", var5); +\n }\n\n if (fingerprint != null) {\n Instant now = Instant.now(); +\n Instant threshold = Instant.ofEpochSecond(fingerprint.timestamp()).plus(3L, ChronoUnit.DAYS); +\n if (now.isAfter(threshold)) {\n this.openDonationPrompt(options); +\n }\n }\n }\n }\n }\n\n private void openDonationPrompt(SodiumGameOptions options) {\n ScreenPrompt prompt = new ScreenPrompt(\n this, DONATION_PROMPT_MESSAGE, 320, 190, new ScreenPrompt.Action(class_2561.method_43470("Buy us a coffee"), this::openDonationPage)\n ); +\n prompt.method_25365(true); +\n options.notifications.hasSeenDonationPrompt = true; +\n\n try {\n SodiumGameOptions.writeToDisk(options); +\n } catch (IOException var4) {\n SodiumClientMod.logger().error("Failed to update config file", var4); +\n }\n }\n\n public static class_437 createScreen(class_437 currentScreen) {\n return (class_437)(SodiumClientMod.options().isReadOnly()\n ? new ConfigCorruptedScreen(currentScreen, SodiumOptionsGUI::new)\n : new SodiumOptionsGUI(currentScreen)); +\n }\n\n public void setPage(OptionPage page) {\n this.currentPage = page; +\n this.rebuildGUI(); +\n }\n\n protected void method_25426() {\n super.method_25426(); +\n this.rebuildGUI(); +\n if (this.prompt != null) {\n this.prompt.init(); +\n }\n }\n\n private void rebuildGUI() {\n this.controls.clear(); +\n this.method_37067(); +\n if (this.currentPage == null) {\n if (this.pages.isEmpty()) {\n throw new IllegalStateException("No pages are available?!"); +\n }\n\n this.currentPage = (OptionPage)this.pages.get(0); +\n }\n\n this.rebuildGUIPages(); +\n this.rebuildGUIOptions(); +\n this.undoButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 211, this.field_22790 - 30, 65, 20), class_2561.method_43471("sodium.options.buttons.undo"), this::undoChanges\n ); +\n this.applyButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 142, this.field_22790 - 30, 65, 20), class_2561.method_43471("sodium.options.buttons.apply"), this::applyChanges\n ); +\n this.closeButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 73, this.field_22790 - 30, 65, 20), class_2561.method_43471("gui.done"), this::method_25419\n ); +\n this.donateButton = new FlatButtonWidget(\n new Dim2i(this.field_22789 - 128, 6, 100, 20), class_2561.method_43471("sodium.options.buttons.donate"), this::openDonationPage\n ); +\n this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.field_22789 - 26, 6, 20, 20), class_2561.method_43470("x"), this::hideDonationButton); +\n if (SodiumClientMod.options().notifications.hasClearedDonationButton) {\n this.setDonationButtonVisibility(false); +\n }\n\n this.method_37063(this.undoButton); +\n this.method_37063(this.applyButton); +\n this.method_37063(this.closeButton); +\n this.method_37063(this.donateButton); +\n this.method_37063(this.hideDonateButton); +\n }\n\n private void setDonationButtonVisibility(boolean value) {\n this.donateButton.setVisible(value); +\n this.hideDonateButton.setVisible(value); +\n }\n\n private void hideDonationButton() {\n SodiumGameOptions options = SodiumClientMod.options(); +\n options.notifications.hasClearedDonationButton = true; +\n\n try {\n SodiumGameOptions.writeToDisk(options); +\n } catch (IOException var3) {\n throw new RuntimeException("Failed to save configuration", var3); +\n }\n\n this.setDonationButtonVisibility(false); +\n }\n\n private void rebuildGUIPages() {\n int x = 6; +\n int y = 6; +\n\n for (OptionPage page : this.pages) {\n int width = 12 + this.field_22793.method_27525(page.getName()); +\n FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getName(), () -> this.setPage(page)); +\n button.setSelected(this.currentPage == page); +\n x += width + 6; +\n this.method_37063(button); +\n }\n }\n\n private void rebuildGUIOptions() {\n int x = 6; +\n int y = 28; +\n\n for (UnmodifiableIterator var3 = this.currentPage.getGroups().iterator(); +var3.hasNext(); +y += 4) {\n OptionGroup group = (OptionGroup)var3.next(); +\n\n for (UnmodifiableIterator var5 = group.getOptions().iterator(); +var5.hasNext(); +y += 18) {\n Option option = (Option)var5.next(); +\n Control control = option.getControl(); +\n ControlElement element = control.createElement(new Dim2i(x, y, 240, 18)); +\n this.method_37063(element); +\n this.controls.add(element); +\n }\n }\n }\n\n public void method_25394(class_332 graphics, int mouseX, int mouseY, float delta) {\n this.updateControls(); +\n super.method_25394(graphics, this.prompt != null ? -1 : mouseX, this.prompt != null ? -1 : mouseY, delta); +\n if (this.hoveredElement != null) {\n this.renderOptionTooltip(graphics, this.hoveredElement); +\n }\n\n if (this.prompt != null) {\n this.prompt.method_25394(graphics, mouseX, mouseY, delta); +\n }\n }\n\n private void updateControls() {\n ControlElement hovered = (ControlElement)this.getActiveControls()\n .filter(AbstractWidget::isHovered)\n .findFirst()\n .orElse((ControlElement)this.getActiveControls().filter(AbstractWidget::method_25370).findFirst().orElse(null)); +\n boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged); +\n\n for (OptionPage page : this.pages) {\n UnmodifiableIterator var5 = page.getOptions().iterator(); +\n\n while (var5.hasNext()) {\n Option option = (Option)var5.next(); +\n if (option.hasChanged()) {\n hasChanges = true; +\n }\n }\n }\n\n this.applyButton.setEnabled(hasChanges); +\n this.undoButton.setVisible(hasChanges); +\n this.closeButton.setEnabled(!hasChanges); +\n this.hasPendingChanges = hasChanges; +\n this.hoveredElement = hovered; +\n }\n\n private Stream> getAllOptions() {\n return this.pages.stream().flatMap(s -> s.getOptions().stream()); +\n }\n\n private Stream> getActiveControls() {\n return this.controls.stream(); +\n }\n\n private void renderOptionTooltip(class_332 graphics, ControlElement element) {\n Dim2i dim = element.getDimensions(); +\n int textPadding = 3; +\n int boxPadding = 3; +\n int boxY = dim.y(); +\n int boxX = dim.getLimitX() + boxPadding; +\n int boxWidth = Math.min(200, this.field_22789 - boxX - boxPadding); +\n Option option = element.getOption(); +\n int splitWidth = boxWidth - textPadding * 2; +\n List tooltip = new ArrayList(this.field_22793.method_1728(option.getTooltip(), splitWidth)); +\n OptionImpact impact = option.getImpact(); +\n if (impact != null) {\n class_5250 impactText = class_2561.method_43469("sodium.options.performance_impact_string", new Object[]{impact.getLocalizedName()}); +\n tooltip.addAll(this.field_22793.method_1728(impactText.method_27692(class_124.field_1080), splitWidth)); +\n }\n\n int boxHeight = tooltip.size() * 12 + boxPadding; +\n int boxYLimit = boxY + boxHeight; +\n int boxYCutoff = this.field_22790 - 40; +\n if (boxYLimit > boxYCutoff) {\n boxY -= boxYLimit - boxYCutoff; +\n }\n\n graphics.method_25296(boxX, boxY, boxX + boxWidth, boxY + boxHeight, -536870912, -536870912); +\n\n for (int i = 0; +i < tooltip.size(); +i++) {\n graphics.method_35720(this.field_22793, (class_5481)tooltip.get(i), boxX + textPadding, boxY + textPadding + i * 12, -1); +\n }\n }\n\n private void applyChanges() {\n HashSet> dirtyStorages = new HashSet(); +\n EnumSet flags = EnumSet.noneOf(OptionFlag.class); +\n this.getAllOptions().forEach(option -> {\n if (option.hasChanged()) {\n option.applyChanges(); +\n flags.addAll(option.getFlags()); +\n dirtyStorages.add(option.getStorage()); +\n }\n }); +\n class_310 client = class_310.method_1551(); +\n if (client.field_1687 != null) {\n if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) {\n client.field_1769.method_3279(); +\n } else if (flags.contains(OptionFlag.REQUIRES_RENDERER_UPDATE)) {\n client.field_1769.method_3292(); +\n }\n }\n\n if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) {\n client.method_24041((Integer)client.field_1690.method_42563().method_41753()); +\n client.method_1513(); +\n }\n\n if (flags.contains(OptionFlag.REQUIRES_VIDEOMODE_RELOAD)) {\n client.method_22683().method_4475(); +\n }\n\n if (flags.contains(OptionFlag.REQUIRES_GAME_RESTART)) {\n Console.instance().logMessage(MessageLevel.WARN, "sodium.console.game_restart", true, 10.0); +\n }\n\n for (OptionStorage storage : dirtyStorages) {\n storage.save(); +\n }\n }\n\n private void undoChanges() {\n this.getAllOptions().forEach(Option::reset); +\n }\n\n private void openDonationPage() {\n class_156.method_668().method_670("https://caffeinemc.net/donate"); +\n }\n\n public boolean method_25404(int keyCode, int scanCode, int modifiers) {\n if (this.prompt != null && this.prompt.method_25404(keyCode, scanCode, modifiers)) {\n return true; +\n } else if (this.prompt == null && keyCode == 80 && (modifiers & 1) != 0) {\n class_310.method_1551().method_1507(new class_446(this.prevScreen, class_310.method_1551(), class_310.method_1551().field_1690)); +\n return true; +\n } else {\n return super.method_25404(keyCode, scanCode, modifiers); +\n }\n }\n\n public boolean method_25402(double mouseX, double mouseY, int button) {\n if (this.prompt != null) {\n return this.prompt.method_25402(mouseX, mouseY, button); +\n } else {\n boolean clicked = super.method_25402(mouseX, mouseY, button); +\n if (!clicked) {\n this.method_25395(null); +\n return true; +\n } else {\n return clicked; +\n }\n }\n }\n\n public boolean method_25422() {\n return !this.hasPendingChanges; +\n }\n\n public void method_25419() {\n this.field_22787.method_1507(this.prevScreen); +\n }\n\n public List method_25396() {\n return this.prompt == null ? super.method_25396() : this.prompt.getWidgets(); +\n }\n\n @Override\n public void setPrompt(@Nullable ScreenPrompt prompt) {\n this.prompt = prompt; +\n }\n\n @Nullable\n @Override\n public ScreenPrompt getPrompt() {\n return this.prompt; +\n }\n\n @Override\n public Dim2i getDimensions() {\n return new Dim2i(0, 0, this.field_22789, this.field_22790); +\n }\n}\n {"url": "https://caffeinemc.net/donate"} low +5 2 2048cee1aed753e10480183673ffb5e685de2ce414e99e93f7d1dd11a87a19af net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks package net.caffeinemc.mods.sodium.client.compatibility.checks; +\n\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper; +\nimport org.lwjgl.Version; +\n\npublic class PreLaunchChecks {\n private static final String REQUIRED_LWJGL_VERSION = "3.3.3"; +\n\n public static void checkEnvironment() {\n if (BugChecks.ISSUE_2561) {\n checkLwjglRuntimeVersion(); +\n }\n }\n\n private static void checkLwjglRuntimeVersion() {\n if (!isUsingKnownCompatibleLwjglVersion()) {\n String advice; +\n if (isUsingPrismLauncher()) {\n advice = "It appears you are using Prism Launcher to start the game. You can likely fix this problem by opening your instance settings and navigating to the Versionsection in the sidebar."; +\n } else {\n advice = "You must change the LWJGL version in your launcher to continue. This is usually controlled by the settings for a profile or instance in your launcher."; +\n }\n\n String message = "The game failed to start because the currently active LWJGL version is not compatible.\\n\\nInstalled version: ###CURRENT_VERSION###\\nRequired version: ###REQUIRED_VERSION###\\n\\n###ADVICE_STRING###"\n .replace("###CURRENT_VERSION###", Version.getVersion())\n .replace("###REQUIRED_VERSION###", "3.3.3")\n .replace("###ADVICE_STRING###", advice); +\n PlatformHelper.showCriticalErrorAndClose(\n null, "Sodium Renderer - Unsupported LWJGL", message, "https://link.caffeinemc.net/help/sodium/runtime-issue/lwjgl3/gh-2561"\n ); +\n }\n }\n\n private static boolean isUsingKnownCompatibleLwjglVersion() {\n return Version.getVersion().startsWith("3.3.3"); +\n }\n\n private static boolean isUsingPrismLauncher() {\n return getLauncherBrand().equalsIgnoreCase("PrismLauncher"); +\n }\n\n private static String getLauncherBrand() {\n return System.getProperty("minecraft.launcher.brand", "unknown"); +\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/runtime-issue/lwjgl3/gh-2561"} low +6 2 0b9d53bc482f11c0d8c71a9689645132f0a50249838091b3e6f95fefbc279075 net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner package net.caffeinemc.mods.sodium.client.compatibility.checks; +\n\nimport com.sun.jna.Platform; +\nimport com.sun.jna.platform.win32.Kernel32; +\nimport com.sun.jna.platform.win32.Kernel32Util; +\nimport com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W; +\nimport java.nio.file.Files; +\nimport java.nio.file.LinkOption; +\nimport java.nio.file.Path; +\nimport java.util.ArrayList; +\nimport java.util.Collections; +\nimport java.util.List; +\nimport net.caffeinemc.mods.sodium.client.platform.MessageBox; +\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.Version; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionInfo; +\nimport org.jetbrains.annotations.Nullable; +\nimport org.slf4j.Logger; +\nimport org.slf4j.LoggerFactory; +\n\npublic class ModuleScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-Win32ModuleChecks"); +\n private static final String[] RTSS_HOOKS_MODULE_NAMES = new String[]{"RTSSHooks64.dll", "RTSSHooks.dll"}; +\n private static final String[] ASUS_GPU_TWEAK_MODULE_NAMES = new String[]{\n "GTIII-OSD64-GL.dll", "GTIII-OSD-GL.dll", "GTIII-OSD64-VK.dll", "GTIII-OSD-VK.dll", "GTIII-OSD64.dll", "GTIII-OSD.dll"\n }; +\n\n public static void checkModules(NativeWindowHandle window) {\n List modules; +\n try {\n modules = listModules(); +\n } catch (Throwable var3) {\n LOGGER.warn("Failed to scan the currently loaded modules", var3); +\n return; +\n }\n\n if (!modules.isEmpty()) {\n if (BugChecks.ISSUE_2048 && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {\n checkRTSSModules(window); +\n }\n\n if (BugChecks.ISSUE_2637 && isModuleLoaded(modules, ASUS_GPU_TWEAK_MODULE_NAMES)) {\n checkASUSGpuTweakIII(window); +\n }\n }\n }\n\n private static List listModules() {\n if (!Platform.isWindows()) {\n return List.of(); +\n } else {\n int pid = Kernel32.INSTANCE.GetCurrentProcessId(); +\n ArrayList modules = new ArrayList(); +\n\n for (MODULEENTRY32W module : Kernel32Util.getModules(pid)) {\n modules.add(module.szModule()); +\n }\n\n return Collections.unmodifiableList(modules); +\n }\n }\n\n private static void checkRTSSModules(NativeWindowHandle window) {\n LOGGER.warn("RivaTuner Statistics Server (RTSS) has injected into the process! Attempting to apply workarounds for compatibility..."); +\n WindowsFileVersion version = null; +\n\n try {\n version = findRTSSModuleVersion(); +\n } catch (Throwable var3) {\n LOGGER.warn("Exception thrown while reading file version", var3); +\n }\n\n if (version == null) {\n LOGGER.warn("Could not determine version of RivaTuner Statistics Server"); +\n } else {\n LOGGER.info("Detected RivaTuner Statistics Server version: {}", version); +\n }\n\n if (version == null || !isRTSSCompatible(version)) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium.\\n\\nYou must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n ); +\n throw new RuntimeException(\n "The installed version of RivaTuner Statistics Server (RTSS) is not compatible with Sodium, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n ); +\n }\n }\n\n private static boolean isRTSSCompatible(WindowsFileVersion version) {\n int x = version.x(); +\n int y = version.y(); +\n int z = version.z(); +\n return x > 7 || x == 7 && y > 3 || x == 7 && y == 3 && z >= 4; +\n }\n\n private static void checkASUSGpuTweakIII(NativeWindowHandle window) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "ASUS GPU Tweak III is not compatible with Minecraft, and causes extreme performance issues and severe graphical corruption when used with Minecraft.\\n\\nYou *must* do one of the following things to continue:\\n\\na) Open the settings of ASUS GPU Tweak III, enable the Blacklist option, click \\"Browse from file...\\", and select the Java runtime (javaw.exe) which is used by Minecraft.\\n\\nb) Completely uninstall the ASUS GPU Tweak III application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n ); +\n throw new RuntimeException(\n "ASUS GPU Tweak III is not compatible with Minecraft, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n ); +\n }\n\n @Nullable\n private static WindowsFileVersion findRTSSModuleVersion() {\n long module; +\n try {\n module = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleHandleByNames(RTSS_HOOKS_MODULE_NAMES); +\n } catch (Throwable var9) {\n LOGGER.warn("Failed to locate module", var9); +\n return null; +\n }\n\n String moduleFileName; +\n try {\n moduleFileName = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleFileName(module); +\n } catch (Throwable var8) {\n LOGGER.warn("Failed to get path of module", var8); +\n return null; +\n }\n\n Path modulePath = Path.of(moduleFileName); +\n Path moduleDirectory = modulePath.getParent(); +\n LOGGER.info("Searching directory: {}", moduleDirectory); +\n Path executablePath = moduleDirectory.resolve("RTSS.exe"); +\n if (!Files.exists(executablePath, new LinkOption[0])) {\n LOGGER.warn("Could not find executable: {}", executablePath); +\n return null; +\n } else {\n LOGGER.info("Parsing file: {}", executablePath); +\n VersionInfo version = Version.getModuleFileVersion(executablePath.toAbsolutePath().toString()); +\n if (version == null) {\n LOGGER.warn("Couldn't find version structure"); +\n return null; +\n } else {\n VersionFixedFileInfoStruct fileVersion = version.queryFixedFileInfo(); +\n if (fileVersion == null) {\n LOGGER.warn("Couldn't query file version"); +\n return null; +\n } else {\n return WindowsFileVersion.fromFileVersion(fileVersion); +\n }\n }\n }\n }\n\n private static boolean isModuleLoaded(List modules, String[] names) {\n for (String name : names) {\n for (String module : modules) {\n if (module.equalsIgnoreCase(name)) {\n return true; +\n }\n }\n }\n\n return false; +\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"} low +7 2 c7ef03b142e9371c5b10fd54ee7a22060872bd3addb96c6fa21ab10ccdc4b481 net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner package net.caffeinemc.mods.sodium.client.compatibility.checks; +\n\nimport com.sun.jna.Platform; +\nimport com.sun.jna.platform.win32.Kernel32; +\nimport com.sun.jna.platform.win32.Kernel32Util; +\nimport com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W; +\nimport java.nio.file.Files; +\nimport java.nio.file.LinkOption; +\nimport java.nio.file.Path; +\nimport java.util.ArrayList; +\nimport java.util.Collections; +\nimport java.util.List; +\nimport net.caffeinemc.mods.sodium.client.platform.MessageBox; +\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.Version; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionInfo; +\nimport org.jetbrains.annotations.Nullable; +\nimport org.slf4j.Logger; +\nimport org.slf4j.LoggerFactory; +\n\npublic class ModuleScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-Win32ModuleChecks"); +\n private static final String[] RTSS_HOOKS_MODULE_NAMES = new String[]{"RTSSHooks64.dll", "RTSSHooks.dll"}; +\n private static final String[] ASUS_GPU_TWEAK_MODULE_NAMES = new String[]{\n "GTIII-OSD64-GL.dll", "GTIII-OSD-GL.dll", "GTIII-OSD64-VK.dll", "GTIII-OSD-VK.dll", "GTIII-OSD64.dll", "GTIII-OSD.dll"\n }; +\n\n public static void checkModules(NativeWindowHandle window) {\n List modules; +\n try {\n modules = listModules(); +\n } catch (Throwable var3) {\n LOGGER.warn("Failed to scan the currently loaded modules", var3); +\n return; +\n }\n\n if (!modules.isEmpty()) {\n if (BugChecks.ISSUE_2048 && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {\n checkRTSSModules(window); +\n }\n\n if (BugChecks.ISSUE_2637 && isModuleLoaded(modules, ASUS_GPU_TWEAK_MODULE_NAMES)) {\n checkASUSGpuTweakIII(window); +\n }\n }\n }\n\n private static List listModules() {\n if (!Platform.isWindows()) {\n return List.of(); +\n } else {\n int pid = Kernel32.INSTANCE.GetCurrentProcessId(); +\n ArrayList modules = new ArrayList(); +\n\n for (MODULEENTRY32W module : Kernel32Util.getModules(pid)) {\n modules.add(module.szModule()); +\n }\n\n return Collections.unmodifiableList(modules); +\n }\n }\n\n private static void checkRTSSModules(NativeWindowHandle window) {\n LOGGER.warn("RivaTuner Statistics Server (RTSS) has injected into the process! Attempting to apply workarounds for compatibility..."); +\n WindowsFileVersion version = null; +\n\n try {\n version = findRTSSModuleVersion(); +\n } catch (Throwable var3) {\n LOGGER.warn("Exception thrown while reading file version", var3); +\n }\n\n if (version == null) {\n LOGGER.warn("Could not determine version of RivaTuner Statistics Server"); +\n } else {\n LOGGER.info("Detected RivaTuner Statistics Server version: {}", version); +\n }\n\n if (version == null || !isRTSSCompatible(version)) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium.\\n\\nYou must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n ); +\n throw new RuntimeException(\n "The installed version of RivaTuner Statistics Server (RTSS) is not compatible with Sodium, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"\n ); +\n }\n }\n\n private static boolean isRTSSCompatible(WindowsFileVersion version) {\n int x = version.x(); +\n int y = version.y(); +\n int z = version.z(); +\n return x > 7 || x == 7 && y > 3 || x == 7 && y == 3 && z >= 4; +\n }\n\n private static void checkASUSGpuTweakIII(NativeWindowHandle window) {\n MessageBox.showMessageBox(\n window,\n MessageBox.IconType.ERROR,\n "Sodium Renderer",\n "ASUS GPU Tweak III is not compatible with Minecraft, and causes extreme performance issues and severe graphical corruption when used with Minecraft.\\n\\nYou *must* do one of the following things to continue:\\n\\na) Open the settings of ASUS GPU Tweak III, enable the Blacklist option, click \\"Browse from file...\\", and select the Java runtime (javaw.exe) which is used by Minecraft.\\n\\nb) Completely uninstall the ASUS GPU Tweak III application.\\n\\nFor more information on how to solve this problem, click the 'Help' button.",\n "https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n ); +\n throw new RuntimeException(\n "ASUS GPU Tweak III is not compatible with Minecraft, see here for more details: https://link.caffeinemc.net/help/sodium/incompatible-software/asus-gtiii/gh-2637"\n ); +\n }\n\n @Nullable\n private static WindowsFileVersion findRTSSModuleVersion() {\n long module; +\n try {\n module = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleHandleByNames(RTSS_HOOKS_MODULE_NAMES); +\n } catch (Throwable var9) {\n LOGGER.warn("Failed to locate module", var9); +\n return null; +\n }\n\n String moduleFileName; +\n try {\n moduleFileName = net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32.getModuleFileName(module); +\n } catch (Throwable var8) {\n LOGGER.warn("Failed to get path of module", var8); +\n return null; +\n }\n\n Path modulePath = Path.of(moduleFileName); +\n Path moduleDirectory = modulePath.getParent(); +\n LOGGER.info("Searching directory: {}", moduleDirectory); +\n Path executablePath = moduleDirectory.resolve("RTSS.exe"); +\n if (!Files.exists(executablePath, new LinkOption[0])) {\n LOGGER.warn("Could not find executable: {}", executablePath); +\n return null; +\n } else {\n LOGGER.info("Parsing file: {}", executablePath); +\n VersionInfo version = Version.getModuleFileVersion(executablePath.toAbsolutePath().toString()); +\n if (version == null) {\n LOGGER.warn("Couldn't find version structure"); +\n return null; +\n } else {\n VersionFixedFileInfoStruct fileVersion = version.queryFixedFileInfo(); +\n if (fileVersion == null) {\n LOGGER.warn("Couldn't query file version"); +\n return null; +\n } else {\n return WindowsFileVersion.fromFileVersion(fileVersion); +\n }\n }\n }\n }\n\n private static boolean isModuleLoaded(List modules, String[] names) {\n for (String name : names) {\n for (String module : modules) {\n if (module.equalsIgnoreCase(name)) {\n return true; +\n }\n }\n }\n\n return false; +\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/incompatible-software/rivatuner-statistics-server/gh-2048"} low +8 2 54aa6d079497c9fc459f84c660a303496d18fa17c35c0e22cbe2160924de212e net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks package net.caffeinemc.mods.sodium.client.compatibility.checks; +\n\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo; +\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; +\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion; +\n\nclass GraphicsDriverChecks {\n static void postContextInit(NativeWindowHandle window, GlContextInfo context) {\n GraphicsAdapterVendor vendor = GraphicsAdapterVendor.fromContext(context); +\n if (vendor != GraphicsAdapterVendor.UNKNOWN) {\n if (vendor == GraphicsAdapterVendor.INTEL && BugChecks.ISSUE_899) {\n WindowsFileVersion installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899(); +\n if (installedVersion != null) {\n String installedVersionString = installedVersion.toString(); +\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed Intel Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 10.18.10.5161 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"\n ); +\n }\n }\n\n if (vendor == GraphicsAdapterVendor.NVIDIA && BugChecks.ISSUE_1486) {\n WindowsFileVersion installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486(); +\n if (installedVersion != null) {\n String installedVersionString = NvidiaDriverVersion.parse(installedVersion).toString(); +\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed NVIDIA Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 536.23 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"\n ); +\n }\n }\n }\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"} low +9 2 5ff865ff6c2e250096fb15b9a943c645deb8558eddc72fa1b492748eb2c78b32 net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks package net.caffeinemc.mods.sodium.client.compatibility.checks; +\n\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo; +\nimport net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; +\nimport net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; +\nimport net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +\nimport net.caffeinemc.mods.sodium.client.platform.PlatformHelper; +\nimport net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion; +\n\nclass GraphicsDriverChecks {\n static void postContextInit(NativeWindowHandle window, GlContextInfo context) {\n GraphicsAdapterVendor vendor = GraphicsAdapterVendor.fromContext(context); +\n if (vendor != GraphicsAdapterVendor.UNKNOWN) {\n if (vendor == GraphicsAdapterVendor.INTEL && BugChecks.ISSUE_899) {\n WindowsFileVersion installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899(); +\n if (installedVersion != null) {\n String installedVersionString = installedVersion.toString(); +\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed Intel Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 10.18.10.5161 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"\n ); +\n }\n }\n\n if (vendor == GraphicsAdapterVendor.NVIDIA && BugChecks.ISSUE_1486) {\n WindowsFileVersion installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486(); +\n if (installedVersion != null) {\n String installedVersionString = NvidiaDriverVersion.parse(installedVersion).toString(); +\n PlatformHelper.showCriticalErrorAndClose(\n window,\n "Sodium Renderer - Unsupported Driver",\n "The game failed to start because the currently installed NVIDIA Graphics Driver is not compatible.\\n\\nInstalled version: ###CURRENT_DRIVER###\\nRequired version: 536.23 (or newer)\\n\\nPlease click the 'Help' button to read more about how to fix this problem."\n .replace("###CURRENT_DRIVER###", installedVersionString),\n "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/nvidia/gh-1486"\n ); +\n }\n }\n }\n }\n}\n {"url": "https://link.caffeinemc.net/help/sodium/graphics-driver/windows/intel/gh-899"} low +10 2 dcf24bb91e7861b7a382958053c3efc201684e93df7ce058e849effa3f947fb0 net/caffeinemc/mods/sodium/client/checks/ResourcePackScanner package net.caffeinemc.mods.sodium.client.checks; +\n\nimport java.io.IOException; +\nimport java.util.ArrayList; +\nimport java.util.Collection; +\nimport java.util.List; +\nimport java.util.Set; +\nimport net.caffeinemc.mods.sodium.client.console.Console; +\nimport net.caffeinemc.mods.sodium.client.console.message.MessageLevel; +\nimport net.minecraft.class_3258; +\nimport net.minecraft.class_3259; +\nimport net.minecraft.class_3262; +\nimport net.minecraft.class_3264; +\nimport net.minecraft.class_3300; +\nimport org.jetbrains.annotations.NotNull; +\nimport org.slf4j.Logger; +\nimport org.slf4j.LoggerFactory; +\n\npublic class ResourcePackScanner {\n private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-ResourcePackScanner"); +\n private static final Set SHADER_PROGRAM_BLACKLIST = Set.of(\n "rendertype_solid.vsh",\n "rendertype_solid.fsh",\n "rendertype_solid.json",\n "rendertype_cutout_mipped.vsh",\n "rendertype_cutout_mipped.fsh",\n "rendertype_cutout_mipped.json",\n "rendertype_cutout.vsh",\n "rendertype_cutout.fsh",\n "rendertype_cutout.json",\n "rendertype_translucent.vsh",\n "rendertype_translucent.fsh",\n "rendertype_translucent.json",\n "rendertype_tripwire.vsh",\n "rendertype_tripwire.fsh",\n "rendertype_tripwire.json",\n "rendertype_clouds.vsh",\n "rendertype_clouds.fsh",\n "rendertype_clouds.json"\n ); +\n private static final Set SHADER_INCLUDE_BLACKLIST = Set.of("light.glsl", "fog.glsl"); +\n\n public static void checkIfCoreShaderLoaded(class_3300 manager) {\n List outputs = manager.method_29213()\n .filter(ResourcePackScanner::isExternalResourcePack)\n .map(ResourcePackScanner::scanResources)\n .toList(); +\n printToasts(outputs); +\n printCompatibilityReport(outputs); +\n }\n\n private static void printToasts(Collection resourcePacks) {\n List incompatibleResourcePacks = resourcePacks.stream().filter(pack -> !pack.shaderPrograms.isEmpty()).toList(); +\n List likelyIncompatibleResourcePacks = resourcePacks.stream()\n .filter(pack -> !pack.shaderIncludes.isEmpty())\n .filter(pack -> !incompatibleResourcePacks.contains(pack))\n .toList(); +\n boolean shown = false; +\n if (!incompatibleResourcePacks.isEmpty()) {\n showConsoleMessage("sodium.console.core_shaders_error", true, MessageLevel.SEVERE); +\n\n for (ResourcePackScanner.ScannedResourcePack entry : incompatibleResourcePacks) {\n showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.SEVERE); +\n }\n\n shown = true; +\n }\n\n if (!likelyIncompatibleResourcePacks.isEmpty()) {\n showConsoleMessage("sodium.console.core_shaders_warn", true, MessageLevel.WARN); +\n\n for (ResourcePackScanner.ScannedResourcePack entry : likelyIncompatibleResourcePacks) {\n showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.WARN); +\n }\n\n shown = true; +\n }\n\n if (shown) {\n showConsoleMessage("sodium.console.core_shaders_info", true, MessageLevel.INFO); +\n }\n }\n\n private static void printCompatibilityReport(Collection scanResults) {\n StringBuilder builder = new StringBuilder(); +\n\n for (ResourcePackScanner.ScannedResourcePack entry : scanResults) {\n if (!entry.shaderPrograms.isEmpty() || !entry.shaderIncludes.isEmpty()) {\n builder.append("- Resource pack: ").append(getResourcePackName(entry.resourcePack)).append("\\n"); +\n if (!entry.shaderPrograms.isEmpty()) {\n emitProblem(\n builder,\n "The resource pack replaces terrain shaders, which are not supported",\n "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs",\n entry.shaderPrograms\n ); +\n }\n\n if (!entry.shaderIncludes.isEmpty()) {\n emitProblem(\n builder,\n "The resource pack modifies shader include files, which are not fully supported",\n "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs",\n entry.shaderIncludes\n ); +\n }\n }\n }\n\n if (!builder.isEmpty()) {\n LOGGER.error("The following compatibility issues were found with installed resource packs:\\n{}", builder); +\n }\n }\n\n private static void emitProblem(StringBuilder builder, String description, String url, List resources) {\n builder.append("\\t- Problem found: ").append("\\n"); +\n builder.append("\\t\\t- Description:\\n\\t\\t\\t").append(description).append("\\n"); +\n builder.append("\\t\\t- More information: ").append(url).append("\\n"); +\n builder.append("\\t\\t- Files: ").append("\\n"); +\n\n for (String resource : resources) {\n builder.append("\\t\\t\\t- ").append(resource).append("\\n"); +\n }\n }\n\n @NotNull\n private static ResourcePackScanner.ScannedResourcePack scanResources(class_3262 resourcePack) {\n List ignoredShaders = determineIgnoredShaders(resourcePack); +\n if (!ignoredShaders.isEmpty()) {\n LOGGER.warn(\n "Resource pack '{}' indicates the following shaders should be ignored: {}", getResourcePackName(resourcePack), String.join(", ", ignoredShaders)\n ); +\n }\n\n ArrayList unsupportedShaderPrograms = new ArrayList(); +\n ArrayList unsupportedShaderIncludes = new ArrayList(); +\n resourcePack.method_14408(class_3264.field_14188, "minecraft", "shaders", (identifier, supplier) -> {\n String path = identifier.method_12832(); +\n String name = path.substring(path.lastIndexOf(47) + 1); +\n if (!ignoredShaders.contains(name)) {\n if (SHADER_PROGRAM_BLACKLIST.contains(name)) {\n unsupportedShaderPrograms.add(path); +\n } else if (SHADER_INCLUDE_BLACKLIST.contains(name)) {\n unsupportedShaderIncludes.add(path); +\n }\n }\n }); +\n return new ResourcePackScanner.ScannedResourcePack(resourcePack, unsupportedShaderPrograms, unsupportedShaderIncludes); +\n }\n\n private static boolean isExternalResourcePack(class_3262 pack) {\n return pack instanceof class_3259 || pack instanceof class_3258; +\n }\n\n private static String getResourcePackName(class_3262 pack) {\n String path = pack.method_14409(); +\n return path.startsWith("file/") ? path.substring(5) : path; +\n }\n\n private static List determineIgnoredShaders(class_3262 resourcePack) {\n ArrayList ignoredShaders = new ArrayList(); +\n\n try {\n SodiumResourcePackMetadata meta = (SodiumResourcePackMetadata)resourcePack.method_14407(SodiumResourcePackMetadata.SERIALIZER); +\n if (meta != null) {\n ignoredShaders.addAll(meta.ignoredShaders()); +\n }\n } catch (IOException var3) {\n LOGGER.error("Failed to load pack.mcmeta file for resource pack '{}'", resourcePack.method_14409()); +\n }\n\n return ignoredShaders; +\n }\n\n private static void showConsoleMessage(String message, boolean translatable, MessageLevel messageLevel) {\n Console.instance().logMessage(messageLevel, message, translatable, 12.5); +\n }\n\n private record ScannedResourcePack(class_3262 resourcePack, ArrayList shaderPrograms, ArrayList shaderIncludes) {\n }\n}\n {"url": "https://github.com/CaffeineMC/sodium/wiki/Resource-Packs"} low 11 3 fc7e089f517eab447befde28ce1b5b2438bc5a08131eb338adeaaacbdef7d6cf net/fabricmc/fabric/impl/base/event/EventFactoryImpl \N {} low -12 4 967302d02a45f4cfa29af6604a50d12097295caa1aabff33b1a3d8e7638f9962 net/caffeinemc/mods/sodium/client/platform/windows/WindowsFileVersion package net.caffeinemc.mods.sodium.client.platform.windows;\n\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct;\nimport org.jetbrains.annotations.NotNull;\n\npublic record WindowsFileVersion(int x, int y, int z, int w) {\n @NotNull\n public static WindowsFileVersion fromFileVersion(VersionFixedFileInfoStruct fileVersion) {\n int x = fileVersion.getFileVersionMostSignificantBits() >>> 16 & 65535;\n int y = fileVersion.getFileVersionMostSignificantBits() >>> 0 & 65535;\n int z = fileVersion.getFileVersionLeastSignificantBits() >>> 16 & 65535;\n int w = fileVersion.getFileVersionLeastSignificantBits() >>> 0 & 65535;\n return new WindowsFileVersion(x, y, z, w);\n }\n\n public String toString() {\n return "%s.%s.%s.%s".formatted(this.x, this.y, this.z, this.w);\n }\n}\n {} high -13 5 7005a5b5d443c84d758eceb963351a357d93b5c15eeb19caf20aae99d65a623b net/caffeinemc/mods/sodium/desktop/LaunchWarn package net.caffeinemc.mods.sodium.desktop;\n\nimport java.awt.GraphicsEnvironment;\nimport java.io.IOException;\nimport javax.swing.JDialog;\nimport javax.swing.JOptionPane;\nimport javax.swing.UIManager;\nimport javax.swing.UnsupportedLookAndFeelException;\nimport net.caffeinemc.mods.sodium.desktop.utils.browse.BrowseUrlHandler;\n\npublic class LaunchWarn {\n private static final String HELP_URL = "https://link.caffeinemc.net/guides/sodium/installation";\n private static final String RICH_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

";\n private static final String FALLBACK_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

";\n private static final String FAILED_TO_BROWSE_MESSAGE = "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

";\n public static final String WINDOW_TITLE = "Sodium";\n\n public static void main(String[] args) {\n if (GraphicsEnvironment.isHeadless()) {\n showHeadlessError();\n } else {\n showGraphicalError();\n }\n }\n\n private static void showHeadlessError() {\n System.err\n .println(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"\n );\n }\n\n private static void showGraphicalError() {\n trySetSystemLookAndFeel();\n trySetSystemFontPreferences();\n BrowseUrlHandler browseUrlHandler = BrowseUrlHandler.createImplementation();\n if (browseUrlHandler != null) {\n showRichGraphicalDialog(browseUrlHandler);\n } else {\n showFallbackGraphicalDialog();\n }\n\n System.exit(0);\n }\n\n private static void showRichGraphicalDialog(BrowseUrlHandler browseUrlHandler) {\n int selectedOption = showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

",\n "Sodium",\n 0,\n 1,\n new String[]{"Help", "Close"},\n 0\n );\n if (selectedOption == 0) {\n log("Opening URL: https://link.caffeinemc.net/guides/sodium/installation");\n\n try {\n browseUrlHandler.browseTo("https://link.caffeinemc.net/guides/sodium/installation");\n } catch (IOException var3) {\n log("Failed to open default web browser!", var3);\n showDialogBox(\n "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

",\n "Sodium",\n -1,\n 2,\n null,\n -1\n );\n }\n }\n }\n\n private static void showFallbackGraphicalDialog() {\n showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

",\n "Sodium",\n -1,\n 1,\n null,\n null\n );\n }\n\n private static int showDialogBox(String message, String title, int optionType, int messageType, String[] options, Object initialValue) {\n JOptionPane pane = new JOptionPane(message, messageType, optionType, null, options, initialValue);\n JDialog dialog = pane.createDialog(title);\n dialog.setVisible(true);\n Object selectedValue = pane.getValue();\n if (selectedValue == null) {\n return -1;\n } else if (options == null) {\n return selectedValue instanceof Integer ? (Integer)selectedValue : -1;\n } else {\n for (int counter = 0; counter < options.length; counter++) {\n String option = options[counter];\n if (option.equals(selectedValue)) {\n return counter;\n }\n }\n\n return -1;\n }\n }\n\n private static void trySetSystemLookAndFeel() {\n try {\n UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());\n } catch (UnsupportedLookAndFeelException | ReflectiveOperationException var1) {\n }\n }\n\n private static void trySetSystemFontPreferences() {\n System.setProperty("awt.useSystemAAFontSettings", "on");\n }\n\n private static void log(String message) {\n System.err.println(message);\n }\n\n private static void log(String message, Throwable exception) {\n System.err.println(message);\n exception.printStackTrace(System.err);\n }\n}\n {} low +12 4 967302d02a45f4cfa29af6604a50d12097295caa1aabff33b1a3d8e7638f9962 net/caffeinemc/mods/sodium/client/platform/windows/WindowsFileVersion package net.caffeinemc.mods.sodium.client.platform.windows; +\n\nimport net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionFixedFileInfoStruct; +\nimport org.jetbrains.annotations.NotNull; +\n\npublic record WindowsFileVersion(int x, int y, int z, int w) {\n @NotNull\n public static WindowsFileVersion fromFileVersion(VersionFixedFileInfoStruct fileVersion) {\n int x = fileVersion.getFileVersionMostSignificantBits() >>> 16 & 65535; +\n int y = fileVersion.getFileVersionMostSignificantBits() >>> 0 & 65535; +\n int z = fileVersion.getFileVersionLeastSignificantBits() >>> 16 & 65535; +\n int w = fileVersion.getFileVersionLeastSignificantBits() >>> 0 & 65535; +\n return new WindowsFileVersion(x, y, z, w); +\n }\n\n public String toString() {\n return "%s.%s.%s.%s".formatted(this.x, this.y, this.z, this.w); +\n }\n}\n {} high +13 5 7005a5b5d443c84d758eceb963351a357d93b5c15eeb19caf20aae99d65a623b net/caffeinemc/mods/sodium/desktop/LaunchWarn package net.caffeinemc.mods.sodium.desktop; +\n\nimport java.awt.GraphicsEnvironment; +\nimport java.io.IOException; +\nimport javax.swing.JDialog; +\nimport javax.swing.JOptionPane; +\nimport javax.swing.UIManager; +\nimport javax.swing.UnsupportedLookAndFeelException; +\nimport net.caffeinemc.mods.sodium.desktop.utils.browse.BrowseUrlHandler; +\n\npublic class LaunchWarn {\n private static final String HELP_URL = "https://link.caffeinemc.net/guides/sodium/installation"; +\n private static final String RICH_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

"; +\n private static final String FALLBACK_MESSAGE = "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"; +\n private static final String FAILED_TO_BROWSE_MESSAGE = "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

"; +\n public static final String WINDOW_TITLE = "Sodium"; +\n\n public static void main(String[] args) {\n if (GraphicsEnvironment.isHeadless()) {\n showHeadlessError(); +\n } else {\n showGraphicalError(); +\n }\n }\n\n private static void showHeadlessError() {\n System.err\n .println(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

"\n ); +\n }\n\n private static void showGraphicalError() {\n trySetSystemLookAndFeel(); +\n trySetSystemFontPreferences(); +\n BrowseUrlHandler browseUrlHandler = BrowseUrlHandler.createImplementation(); +\n if (browseUrlHandler != null) {\n showRichGraphicalDialog(browseUrlHandler); +\n } else {\n showFallbackGraphicalDialog(); +\n }\n\n System.exit(0); +\n }\n\n private static void showRichGraphicalDialog(BrowseUrlHandler browseUrlHandler) {\n int selectedOption = showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then click the \\"Help\\" button for an installation guide.

",\n "Sodium",\n 0,\n 1,\n new String[]{"Help", "Close"},\n 0\n ); +\n if (selectedOption == 0) {\n log("Opening URL: https://link.caffeinemc.net/guides/sodium/installation"); +\n\n try {\n browseUrlHandler.browseTo("https://link.caffeinemc.net/guides/sodium/installation"); +\n } catch (IOException var3) {\n log("Failed to open default web browser!", var3); +\n showDialogBox(\n "

Failed to open the default browser! Your system may be misconfigured. Please open the URL https://link.caffeinemc.net/guides/sodium/installation manually.

",\n "Sodium",\n -1,\n 2,\n null,\n -1\n ); +\n }\n }\n }\n\n private static void showFallbackGraphicalDialog() {\n showDialogBox(\n "

You have tried to launch Sodium (a Minecraft mod) directly, but it is not an executable program or mod installer. Instead, you must install Fabric Loader for Minecraft, and then place this file in your mods directory.

If this is your first time installing mods with Fabric Loader, then visit https://link.caffeinemc.net/guides/sodium/installation for an installation guide.

",\n "Sodium",\n -1,\n 1,\n null,\n null\n ); +\n }\n\n private static int showDialogBox(String message, String title, int optionType, int messageType, String[] options, Object initialValue) {\n JOptionPane pane = new JOptionPane(message, messageType, optionType, null, options, initialValue); +\n JDialog dialog = pane.createDialog(title); +\n dialog.setVisible(true); +\n Object selectedValue = pane.getValue(); +\n if (selectedValue == null) {\n return -1; +\n } else if (options == null) {\n return selectedValue instanceof Integer ? (Integer)selectedValue : -1; +\n } else {\n for (int counter = 0; +counter < options.length; +counter++) {\n String option = options[counter]; +\n if (option.equals(selectedValue)) {\n return counter; +\n }\n }\n\n return -1; +\n }\n }\n\n private static void trySetSystemLookAndFeel() {\n try {\n UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); +\n } catch (UnsupportedLookAndFeelException | ReflectiveOperationException var1) {\n }\n }\n\n private static void trySetSystemFontPreferences() {\n System.setProperty("awt.useSystemAAFontSettings", "on"); +\n }\n\n private static void log(String message) {\n System.err.println(message); +\n }\n\n private static void log(String message, Throwable exception) {\n System.err.println(message); +\n exception.printStackTrace(System.err); +\n }\n}\n {} low \. -- --- Name: delphi_report_issue_details_id_seq; Type: SEQUENCE SET; Schema: public; Owner: labrinth +-- Name: delphi_report_issue_details_id_seq; +Type: SEQUENCE SET; +Schema: public; +Owner: labrinth -- SELECT pg_catalog.setval('public.delphi_report_issue_details_id_seq', 13, true); - -- -- Name: delphi_report_issues_id_seq; Type: SEQUENCE SET; Schema: public; Owner: labrinth -- -SELECT pg_catalog.setval('public.delphi_report_issues_id_seq', 5, true); - +SELECT pg_catalog.setval('public.delphi_report_issues_id_seq', 5, TRUE); -- -- Name: delphi_reports_id_seq; Type: SEQUENCE SET; Schema: public; Owner: labrinth -- -SELECT pg_catalog.setval('public.delphi_reports_id_seq', 1, true); - +SELECT pg_catalog.setval('public.delphi_reports_id_seq', 1, TRUE); -- -- PostgreSQL database dump complete -- \unrestrict RGysBmMc8KFBQ9AssusGyNPozUiB43hdmIPxlv5KSWbX7tdW7XVMPpMginvod9K +; diff --git a/apps/labrinth/migrations/20251024182919_subscription_affiliations.sql b/apps/labrinth/migrations/20251024182919_subscription_affiliations.sql index 1369fb7a71..bc480590d0 100644 --- a/apps/labrinth/migrations/20251024182919_subscription_affiliations.sql +++ b/apps/labrinth/migrations/20251024182919_subscription_affiliations.sql @@ -1,17 +1,17 @@ CREATE TABLE users_subscriptions_affiliations ( - subscription_id BIGINT NOT NULL REFERENCES users_subscriptions(id), - affiliate_code BIGINT NOT NULL REFERENCES affiliate_codes(id), - created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - deactivated_at TIMESTAMPTZ, + subscription_id BIGINT NOT NULL REFERENCES users_subscriptions (id), + affiliate_code BIGINT NOT NULL REFERENCES affiliate_codes (id), + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + deactivated_at TIMESTAMPTZ, UNIQUE (subscription_id) ); -CREATE TABLE users_subscriptions_affiliations_payouts( - id BIGSERIAL PRIMARY KEY, - charge_id BIGINT NOT NULL REFERENCES charges(id), - subscription_id BIGINT NOT NULL REFERENCES users_subscriptions(id), - affiliate_code BIGINT NOT NULL REFERENCES affiliate_codes(id), - payout_value_id BIGSERIAL NOT NULL REFERENCES payouts_values(id), +CREATE TABLE users_subscriptions_affiliations_payouts ( + id BIGSERIAL PRIMARY KEY, + charge_id BIGINT NOT NULL REFERENCES charges (id), + subscription_id BIGINT NOT NULL REFERENCES users_subscriptions (id), + affiliate_code BIGINT NOT NULL REFERENCES affiliate_codes (id), + payout_value_id BIGSERIAL NOT NULL REFERENCES payouts_values (id), UNIQUE (charge_id), UNIQUE (payout_value_id) ); diff --git a/apps/labrinth/migrations/20251030125413_decouple_threads_from_projects.sql b/apps/labrinth/migrations/20251030125413_decouple_threads_from_projects.sql index dd5bcc2394..0f78331fae 100644 --- a/apps/labrinth/migrations/20251030125413_decouple_threads_from_projects.sql +++ b/apps/labrinth/migrations/20251030125413_decouple_threads_from_projects.sql @@ -1,5 +1,4 @@ ALTER TABLE threads DROP CONSTRAINT threads_mod_id_fkey, -ADD CONSTRAINT threads_mod_id_fkey -FOREIGN KEY (mod_id) REFERENCES mods(id) -ON DELETE SET NULL; +ADD CONSTRAINT threads_mod_id_fkey FOREIGN KEY (mod_id) REFERENCES mods (id) + ON DELETE SET NULL; diff --git a/apps/labrinth/migrations/20251130173416_delphi_report_verdicts.sql b/apps/labrinth/migrations/20251130173416_delphi_report_verdicts.sql index daa66ce975..24b6966d42 100644 --- a/apps/labrinth/migrations/20251130173416_delphi_report_verdicts.sql +++ b/apps/labrinth/migrations/20251130173416_delphi_report_verdicts.sql @@ -1,2 +1,2 @@ ALTER TABLE delphi_reports -ADD COLUMN status delphi_report_issue_status NOT NULL DEFAULT 'pending'; +ADD COLUMN status DELPHI_REPORT_ISSUE_STATUS NOT NULL DEFAULT 'pending'; diff --git a/apps/labrinth/migrations/20251201171345_store_ids_as_text.sql b/apps/labrinth/migrations/20251201171345_store_ids_as_text.sql index baf8419e3a..30169959f1 100644 --- a/apps/labrinth/migrations/20251201171345_store_ids_as_text.sql +++ b/apps/labrinth/migrations/20251201171345_store_ids_as_text.sql @@ -2,7 +2,8 @@ -- but with `IMMUTABLE` so we can use them in generated columns CREATE OR REPLACE FUNCTION from_base62(input VARCHAR) -RETURNS BIGINT AS $$ +RETURNS BIGINT +AS $$ DECLARE base INT := 62; chars VARCHAR := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; @@ -22,10 +23,13 @@ BEGIN RETURN result; END; -$$ LANGUAGE plpgsql IMMUTABLE; +$$ +LANGUAGE plpgsql +IMMUTABLE; CREATE OR REPLACE FUNCTION to_base62(input BIGINT) -RETURNS VARCHAR AS $$ +RETURNS VARCHAR +AS $$ DECLARE base INT := 62; chars VARCHAR := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; @@ -40,12 +44,14 @@ BEGIN RETURN result; END; -$$ LANGUAGE plpgsql IMMUTABLE; +$$ +LANGUAGE plpgsql +IMMUTABLE; ALTER TABLE mods - ADD COLUMN text_id TEXT GENERATED ALWAYS AS (to_base62(id)) STORED, - ADD COLUMN text_id_lower TEXT GENERATED ALWAYS AS (lower(to_base62(id))) STORED; +ADD COLUMN text_id TEXT GENERATED ALWAYS AS (to_base62(id)) STORED, +ADD COLUMN text_id_lower TEXT GENERATED ALWAYS AS (lower(to_base62(id))) STORED; ALTER TABLE organizations - ADD COLUMN text_id TEXT GENERATED ALWAYS AS (to_base62(id)) STORED, - ADD COLUMN text_id_lower TEXT GENERATED ALWAYS AS (lower(to_base62(id))) STORED; +ADD COLUMN text_id TEXT GENERATED ALWAYS AS (to_base62(id)) STORED, +ADD COLUMN text_id_lower TEXT GENERATED ALWAYS AS (lower(to_base62(id))) STORED; diff --git a/apps/labrinth/migrations/20251217234047_delphi_dedupe_issue_detail_statuses.sql b/apps/labrinth/migrations/20251217234047_delphi_dedupe_issue_detail_statuses.sql index cdaf439502..a7673ff6f7 100644 --- a/apps/labrinth/migrations/20251217234047_delphi_dedupe_issue_detail_statuses.sql +++ b/apps/labrinth/migrations/20251217234047_delphi_dedupe_issue_detail_statuses.sql @@ -2,25 +2,25 @@ ALTER TABLE delphi_report_issue_details DROP COLUMN status; CREATE TABLE delphi_issue_detail_verdicts ( - project_id BIGINT REFERENCES mods(id) + project_id BIGINT REFERENCES mods (id) ON DELETE SET NULL ON UPDATE CASCADE, - detail_key TEXT NOT NULL, - verdict delphi_report_issue_status NOT NULL, + detail_key TEXT NOT NULL, + verdict DELPHI_REPORT_ISSUE_STATUS NOT NULL, PRIMARY KEY (project_id, detail_key) ); CREATE VIEW delphi_issue_details_with_statuses AS -SELECT - drid.*, - m.id AS project_id, - COALESCE(didv.verdict, 'pending') AS status -FROM delphi_report_issue_details drid -INNER JOIN delphi_report_issues dri ON dri.id = drid.issue_id -INNER JOIN delphi_reports dr ON dr.id = dri.report_id -INNER JOIN files f ON f.id = dr.file_id -INNER JOIN versions v ON v.id = f.version_id -INNER JOIN mods m ON m.id = v.mod_id -LEFT JOIN delphi_issue_detail_verdicts didv - ON m.id = didv.project_id - AND drid.key = didv.detail_key; + SELECT + drid.*, + m.id AS project_id, + COALESCE(didv.verdict, 'pending') AS status + FROM + delphi_report_issue_details AS drid + INNER JOIN delphi_report_issues AS dri ON dri.id = drid.issue_id + INNER JOIN delphi_reports AS dr ON dr.id = dri.report_id + INNER JOIN files AS f ON f.id = dr.file_id + INNER JOIN versions AS v ON v.id = f.version_id + INNER JOIN mods AS m ON m.id = v.mod_id + LEFT JOIN delphi_issue_detail_verdicts AS didv + ON m.id = didv.project_id AND drid.key = didv.detail_key; diff --git a/packages/app-lib/Cargo.toml b/packages/app-lib/Cargo.toml index d4343b91a1..25e3502356 100644 --- a/packages/app-lib/Cargo.toml +++ b/packages/app-lib/Cargo.toml @@ -8,18 +8,15 @@ edition.workspace = true ariadne = { workspace = true } async-compression = { workspace = true, features = ["gzip", "tokio"] } async-recursion = { workspace = true } -async-tungstenite = { workspace = true, features = [ - "tokio-runtime", - "tokio-rustls-webpki-roots", -] } +async-tungstenite = { workspace = true, features = ["tokio-runtime", "tokio-rustls-webpki-roots"] } async-walkdir = { workspace = true } async_zip = { workspace = true, features = [ - "bzip2", - "chrono", - "deflate", - "deflate64", - "tokio-fs", - "zstd", + "bzip2", + "chrono", + "deflate", + "deflate64", + "tokio-fs", + "zstd", ] } base64 = { workspace = true } bytemuck = { workspace = true, features = ["extern_crate_alloc"] } @@ -55,16 +52,16 @@ quick-xml = { workspace = true, features = ["async-tokio"] } rand = { workspace = true } regex = { workspace = true } reqwest = { workspace = true, features = [ - "brotli", - "charset", - "deflate", - "gzip", - "http2", - "json", - "macos-system-configuration", - "multipart", - "rustls-tls-webpki-roots", - "stream", + "brotli", + "charset", + "deflate", + "gzip", + "http2", + "json", + "macos-system-configuration", + "multipart", + "rustls-tls-webpki-roots", + "stream", ] } rgb = { workspace = true } serde = { workspace = true, features = ["derive"] } @@ -75,32 +72,27 @@ sha1_smol = { workspace = true } sha2 = { workspace = true } shlex = { workspace = true } sqlx = { workspace = true, features = [ - "json", - "macros", - "migrate", - "runtime-tokio", - "sqlite", - "uuid", + "json", + "macros", + "migrate", + "runtime-tokio", + "sqlite", + "uuid", ] } sysinfo = { workspace = true, features = ["disk", "system"] } tauri = { workspace = true, features = ["unstable"], optional = true } tempfile = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = [ - "fs", - "io-util", - "macros", - "net", - "process", - "sync", - "time", -] } -tokio-util = { workspace = true, features = [ - "compat", - "io", - "io-util", - "time", + "fs", + "io-util", + "macros", + "net", + "process", + "sync", + "time", ] } +tokio-util = { workspace = true, features = ["compat", "io", "io-util", "time"] } tracing = { workspace = true } tracing-error = { workspace = true } tracing-subscriber = { workspace = true, features = ["chrono", "env-filter"] } diff --git a/packages/app-lib/migrations/20251002173041_settings-version.sql b/packages/app-lib/migrations/20251002173041_settings-version.sql index 285b2af6c5..9d4d2ff2d9 100644 --- a/packages/app-lib/migrations/20251002173041_settings-version.sql +++ b/packages/app-lib/migrations/20251002173041_settings-version.sql @@ -1 +1 @@ -ALTER TABLE settings ADD COLUMN version INTEGER NOT NULL DEFAULT 1; \ No newline at end of file +ALTER TABLE settings ADD COLUMN version INTEGER NOT NULL DEFAULT 1; diff --git a/packages/assets/generated-icons.ts b/packages/assets/generated-icons.ts index 060333fe14..49fa2a05c5 100644 --- a/packages/assets/generated-icons.ts +++ b/packages/assets/generated-icons.ts @@ -6,26 +6,26 @@ import _AlignLeftIcon from './icons/align-left.svg?component' import _ArchiveIcon from './icons/archive.svg?component' import _ArrowBigRightDashIcon from './icons/arrow-big-right-dash.svg?component' import _ArrowBigUpDashIcon from './icons/arrow-big-up-dash.svg?component' -import _ArrowDownIcon from './icons/arrow-down.svg?component' import _ArrowDownLeftIcon from './icons/arrow-down-left.svg?component' +import _ArrowDownIcon from './icons/arrow-down.svg?component' import _ArrowLeftRightIcon from './icons/arrow-left-right.svg?component' -import _ArrowUpIcon from './icons/arrow-up.svg?component' import _ArrowUpRightIcon from './icons/arrow-up-right.svg?component' +import _ArrowUpIcon from './icons/arrow-up.svg?component' import _AsteriskIcon from './icons/asterisk.svg?component' import _BadgeCheckIcon from './icons/badge-check.svg?component' import _BadgeDollarSignIcon from './icons/badge-dollar-sign.svg?component' import _BanIcon from './icons/ban.svg?component' -import _BellIcon from './icons/bell.svg?component' import _BellRingIcon from './icons/bell-ring.svg?component' +import _BellIcon from './icons/bell.svg?component' import _BlocksIcon from './icons/blocks.svg?component' import _BoldIcon from './icons/bold.svg?component' -import _BookIcon from './icons/book.svg?component' import _BookOpenIcon from './icons/book-open.svg?component' import _BookTextIcon from './icons/book-text.svg?component' +import _BookIcon from './icons/book.svg?component' import _BookmarkIcon from './icons/bookmark.svg?component' import _BotIcon from './icons/bot.svg?component' -import _BoxIcon from './icons/box.svg?component' import _BoxImportIcon from './icons/box-import.svg?component' +import _BoxIcon from './icons/box.svg?component' import _BracesIcon from './icons/braces.svg?component' import _BrushCleaningIcon from './icons/brush-cleaning.svg?component' import _BugIcon from './icons/bug.svg?component' @@ -33,9 +33,9 @@ import _CalendarIcon from './icons/calendar.svg?component' import _CardIcon from './icons/card.svg?component' import _ChangeSkinIcon from './icons/change-skin.svg?component' import _ChartIcon from './icons/chart.svg?component' -import _CheckIcon from './icons/check.svg?component' import _CheckCheckIcon from './icons/check-check.svg?component' import _CheckCircleIcon from './icons/check-circle.svg?component' +import _CheckIcon from './icons/check.svg?component' import _ChevronDownIcon from './icons/chevron-down.svg?component' import _ChevronLeftIcon from './icons/chevron-left.svg?component' import _ChevronRightIcon from './icons/chevron-right.svg?component' @@ -67,20 +67,20 @@ import _EditIcon from './icons/edit.svg?component' import _EllipsisVerticalIcon from './icons/ellipsis-vertical.svg?component' import _ExpandIcon from './icons/expand.svg?component' import _ExternalIcon from './icons/external.svg?component' -import _EyeIcon from './icons/eye.svg?component' import _EyeOffIcon from './icons/eye-off.svg?component' -import _FileIcon from './icons/file.svg?component' +import _EyeIcon from './icons/eye.svg?component' import _FileArchiveIcon from './icons/file-archive.svg?component' import _FileCodeIcon from './icons/file-code.svg?component' import _FileImageIcon from './icons/file-image.svg?component' import _FileTextIcon from './icons/file-text.svg?component' -import _FilterIcon from './icons/filter.svg?component' +import _FileIcon from './icons/file.svg?component' import _FilterXIcon from './icons/filter-x.svg?component' -import _FolderIcon from './icons/folder.svg?component' +import _FilterIcon from './icons/filter.svg?component' import _FolderArchiveIcon from './icons/folder-archive.svg?component' import _FolderOpenIcon from './icons/folder-open.svg?component' import _FolderSearchIcon from './icons/folder-search.svg?component' import _FolderUpIcon from './icons/folder-up.svg?component' +import _FolderIcon from './icons/folder.svg?component' import _GameIcon from './icons/game.svg?component' import _GapIcon from './icons/gap.svg?component' import _GaugeIcon from './icons/gauge.svg?component' @@ -97,9 +97,9 @@ import _HashIcon from './icons/hash.svg?component' import _Heading1Icon from './icons/heading-1.svg?component' import _Heading2Icon from './icons/heading-2.svg?component' import _Heading3Icon from './icons/heading-3.svg?component' -import _HeartIcon from './icons/heart.svg?component' import _HeartHandshakeIcon from './icons/heart-handshake.svg?component' import _HeartMinusIcon from './icons/heart-minus.svg?component' +import _HeartIcon from './icons/heart.svg?component' import _HistoryIcon from './icons/history.svg?component' import _HomeIcon from './icons/home.svg?component' import _ImageIcon from './icons/image.svg?component' @@ -116,15 +116,15 @@ import _LeftArrowIcon from './icons/left-arrow.svg?component' import _LibraryIcon from './icons/library.svg?component' import _LightBulbIcon from './icons/light-bulb.svg?component' import _LinkIcon from './icons/link.svg?component' -import _ListIcon from './icons/list.svg?component' import _ListBulletedIcon from './icons/list-bulleted.svg?component' import _ListEndIcon from './icons/list-end.svg?component' import _ListFilterIcon from './icons/list-filter.svg?component' import _ListOrderedIcon from './icons/list-ordered.svg?component' -import _LoaderIcon from './icons/loader.svg?component' +import _ListIcon from './icons/list.svg?component' import _LoaderCircleIcon from './icons/loader-circle.svg?component' -import _LockIcon from './icons/lock.svg?component' +import _LoaderIcon from './icons/loader.svg?component' import _LockOpenIcon from './icons/lock-open.svg?component' +import _LockIcon from './icons/lock.svg?component' import _LogInIcon from './icons/log-in.svg?component' import _LogOutIcon from './icons/log-out.svg?component' import _MailIcon from './icons/mail.svg?component' @@ -135,8 +135,8 @@ import _MessageIcon from './icons/message.svg?component' import _MicrophoneIcon from './icons/microphone.svg?component' import _MinimizeIcon from './icons/minimize.svg?component' import _MinusIcon from './icons/minus.svg?component' -import _MonitorIcon from './icons/monitor.svg?component' import _MonitorSmartphoneIcon from './icons/monitor-smartphone.svg?component' +import _MonitorIcon from './icons/monitor.svg?component' import _MoonIcon from './icons/moon.svg?component' import _MoreHorizontalIcon from './icons/more-horizontal.svg?component' import _MoreVerticalIcon from './icons/more-vertical.svg?component' @@ -145,16 +145,16 @@ import _NoSignalIcon from './icons/no-signal.svg?component' import _NotepadTextIcon from './icons/notepad-text.svg?component' import _OmorphiaIcon from './icons/omorphia.svg?component' import _OrganizationIcon from './icons/organization.svg?component' -import _PackageIcon from './icons/package.svg?component' import _PackageClosedIcon from './icons/package-closed.svg?component' import _PackageOpenIcon from './icons/package-open.svg?component' +import _PackageIcon from './icons/package.svg?component' import _PaintbrushIcon from './icons/paintbrush.svg?component' import _PickaxeIcon from './icons/pickaxe.svg?component' import _PlayIcon from './icons/play.svg?component' import _PlugIcon from './icons/plug.svg?component' import _PlusIcon from './icons/plus.svg?component' -import _RadioButtonIcon from './icons/radio-button.svg?component' import _RadioButtonCheckedIcon from './icons/radio-button-checked.svg?component' +import _RadioButtonIcon from './icons/radio-button.svg?component' import _ReceiptTextIcon from './icons/receipt-text.svg?component' import _RedoIcon from './icons/redo.svg?component' import _RefreshCwIcon from './icons/refresh-cw.svg?component' @@ -171,13 +171,13 @@ import _ScaleIcon from './icons/scale.svg?component' import _ScanEyeIcon from './icons/scan-eye.svg?component' import _SearchIcon from './icons/search.svg?component' import _SendIcon from './icons/send.svg?component' -import _ServerIcon from './icons/server.svg?component' import _ServerPlusIcon from './icons/server-plus.svg?component' +import _ServerIcon from './icons/server.svg?component' import _SettingsIcon from './icons/settings.svg?component' import _ShareIcon from './icons/share.svg?component' -import _ShieldIcon from './icons/shield.svg?component' import _ShieldAlertIcon from './icons/shield-alert.svg?component' import _ShieldCheckIcon from './icons/shield-check.svg?component' +import _ShieldIcon from './icons/shield.svg?component' import _SignalIcon from './icons/signal.svg?component' import _SkullIcon from './icons/skull.svg?component' import _SlashIcon from './icons/slash.svg?component' @@ -204,26 +204,26 @@ import _TrashIcon from './icons/trash.svg?component' import _TriangleAlertIcon from './icons/triangle-alert.svg?component' import _UnderlineIcon from './icons/underline.svg?component' import _UndoIcon from './icons/undo.svg?component' -import _UnknownIcon from './icons/unknown.svg?component' import _UnknownDonationIcon from './icons/unknown-donation.svg?component' +import _UnknownIcon from './icons/unknown.svg?component' import _UnlinkIcon from './icons/unlink.svg?component' import _UnplugIcon from './icons/unplug.svg?component' import _UpdatedIcon from './icons/updated.svg?component' import _UploadIcon from './icons/upload.svg?component' -import _UserIcon from './icons/user.svg?component' import _UserCogIcon from './icons/user-cog.svg?component' import _UserPlusIcon from './icons/user-plus.svg?component' import _UserRoundIcon from './icons/user-round.svg?component' import _UserSearchIcon from './icons/user-search.svg?component' import _UserXIcon from './icons/user-x.svg?component' +import _UserIcon from './icons/user.svg?component' import _UsersIcon from './icons/users.svg?component' import _VersionIcon from './icons/version.svg?component' import _WikiIcon from './icons/wiki.svg?component' import _WindowIcon from './icons/window.svg?component' import _WorldIcon from './icons/world.svg?component' import _WrenchIcon from './icons/wrench.svg?component' -import _XIcon from './icons/x.svg?component' import _XCircleIcon from './icons/x-circle.svg?component' +import _XIcon from './icons/x.svg?component' import _ZoomInIcon from './icons/zoom-in.svg?component' import _ZoomOutIcon from './icons/zoom-out.svg?component' @@ -305,8 +305,8 @@ export const FilterIcon = _FilterIcon export const FolderArchiveIcon = _FolderArchiveIcon export const FolderOpenIcon = _FolderOpenIcon export const FolderSearchIcon = _FolderSearchIcon -export const FolderIcon = _FolderIcon export const FolderUpIcon = _FolderUpIcon +export const FolderIcon = _FolderIcon export const GameIcon = _GameIcon export const GapIcon = _GapIcon export const GaugeIcon = _GaugeIcon diff --git a/packages/blog/compiled/index.ts b/packages/blog/compiled/index.ts index 2dcc7450a8..2a28e498de 100644 --- a/packages/blog/compiled/index.ts +++ b/packages/blog/compiled/index.ts @@ -1,38 +1,38 @@ // AUTO-GENERATED FILE - DO NOT EDIT -import { article as a_new_chapter_for_modrinth_servers } from "./a_new_chapter_for_modrinth_servers"; -import { article as accelerating_development } from "./accelerating_development"; -import { article as becoming_sustainable } from "./becoming_sustainable"; -import { article as capital_return } from "./capital_return"; -import { article as carbon_ads } from "./carbon_ads"; -import { article as creator_monetization } from "./creator_monetization"; -import { article as creator_update } from "./creator_update"; -import { article as creator_updates_july_2025 } from "./creator_updates_july_2025"; -import { article as creator_withdrawals_overhaul } from "./creator_withdrawals_overhaul"; -import { article as design_refresh } from "./design_refresh"; -import { article as download_adjustment } from "./download_adjustment"; -import { article as free_server_medal } from "./free_server_medal"; -import { article as knossos_v2_1_0 } from "./knossos_v2_1_0"; -import { article as licensing_guide } from "./licensing_guide"; -import { article as modpack_changes } from "./modpack_changes"; -import { article as modpacks_alpha } from "./modpacks_alpha"; -import { article as modrinth_app_beta } from "./modrinth_app_beta"; -import { article as modrinth_beta } from "./modrinth_beta"; -import { article as modrinth_servers_asia } from "./modrinth_servers_asia"; -import { article as modrinth_servers_beta } from "./modrinth_servers_beta"; -import { article as new_environments } from "./new_environments"; -import { article as new_site_beta } from "./new_site_beta"; -import { article as plugins_resource_packs } from "./plugins_resource_packs"; -import { article as pride_campaign_2025 } from "./pride_campaign_2025"; -import { article as redesign } from "./redesign"; -import { article as russian_censorship } from "./russian_censorship"; -import { article as skins_now_in_modrinth_app } from "./skins_now_in_modrinth_app"; -import { article as standing_by_our_values } from "./standing_by_our_values"; -import { article as standing_by_our_values_russian } from "./standing_by_our_values_russian"; -import { article as streamlined_version_creation } from "./streamlined_version_creation"; +import { article as windows_borderless_malware_disclosure } from "./windows_borderless_malware_disclosure"; +import { article as whats_modrinth } from "./whats_modrinth"; import { article as two_years_of_modrinth } from "./two_years_of_modrinth"; import { article as two_years_of_modrinth_history } from "./two_years_of_modrinth_history"; -import { article as whats_modrinth } from "./whats_modrinth"; -import { article as windows_borderless_malware_disclosure } from "./windows_borderless_malware_disclosure"; +import { article as streamlined_version_creation } from "./streamlined_version_creation"; +import { article as standing_by_our_values } from "./standing_by_our_values"; +import { article as standing_by_our_values_russian } from "./standing_by_our_values_russian"; +import { article as skins_now_in_modrinth_app } from "./skins_now_in_modrinth_app"; +import { article as russian_censorship } from "./russian_censorship"; +import { article as redesign } from "./redesign"; +import { article as pride_campaign_2025 } from "./pride_campaign_2025"; +import { article as plugins_resource_packs } from "./plugins_resource_packs"; +import { article as new_site_beta } from "./new_site_beta"; +import { article as new_environments } from "./new_environments"; +import { article as modrinth_servers_beta } from "./modrinth_servers_beta"; +import { article as modrinth_servers_asia } from "./modrinth_servers_asia"; +import { article as modrinth_beta } from "./modrinth_beta"; +import { article as modrinth_app_beta } from "./modrinth_app_beta"; +import { article as modpacks_alpha } from "./modpacks_alpha"; +import { article as modpack_changes } from "./modpack_changes"; +import { article as licensing_guide } from "./licensing_guide"; +import { article as knossos_v2_1_0 } from "./knossos_v2_1_0"; +import { article as free_server_medal } from "./free_server_medal"; +import { article as download_adjustment } from "./download_adjustment"; +import { article as design_refresh } from "./design_refresh"; +import { article as creator_withdrawals_overhaul } from "./creator_withdrawals_overhaul"; +import { article as creator_updates_july_2025 } from "./creator_updates_july_2025"; +import { article as creator_update } from "./creator_update"; +import { article as creator_monetization } from "./creator_monetization"; +import { article as carbon_ads } from "./carbon_ads"; +import { article as capital_return } from "./capital_return"; +import { article as becoming_sustainable } from "./becoming_sustainable"; +import { article as accelerating_development } from "./accelerating_development"; +import { article as a_new_chapter_for_modrinth_servers } from "./a_new_chapter_for_modrinth_servers"; export const articles = [ windows_borderless_malware_disclosure, diff --git a/packages/ui/src/components/base/DropzoneFileInput.vue b/packages/ui/src/components/base/DropzoneFileInput.vue index 559cd3a533..d406c22d26 100644 --- a/packages/ui/src/components/base/DropzoneFileInput.vue +++ b/packages/ui/src/components/base/DropzoneFileInput.vue @@ -71,7 +71,8 @@ const props = withDefaults( { prompt: 'Drag and drop files or click to browse', primaryPrompt: 'Drag and drop files or click to browse', - secondaryPrompt: 'You can drag files or folders here, or click this area to select file(s) for upload.', + secondaryPrompt: + 'You can drag files or folders here, or click this area to select file(s) for upload.', size: 'standard', }, )