├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── common ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── commonaccesstransformer.cfg │ │ ├── pack.mcmeta │ │ ├── itlt.accesswidener │ │ └── itlt.mixins.json │ │ └── java │ │ └── ga │ │ └── ozli │ │ └── minecraftmods │ │ └── itlt │ │ ├── shared │ │ ├── package-info.java │ │ ├── Constants.java │ │ ├── mixins │ │ │ └── WindowTitleMixin.java │ │ ├── Utils.java │ │ ├── CommonClass.java │ │ ├── client │ │ │ ├── ClientConfig.java │ │ │ ├── ClientUtils.java │ │ │ └── ExtendedGraphicsCard.java │ │ └── CommonConfig.java │ │ └── platform │ │ ├── services │ │ ├── client │ │ │ ├── ClientPlatformHelper.java │ │ │ └── ClientServices.java │ │ └── IPlatformHelper.java │ │ └── Services.java └── build.gradle ├── forge ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ ├── accesstransformer.cfg │ │ │ ├── services │ │ │ └── ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper │ │ │ └── mods.toml │ │ └── java │ │ └── ga │ │ └── ozli │ │ └── minecraftmods │ │ └── itlt │ │ ├── platform │ │ └── ForgePlatformHelper.java │ │ ├── client │ │ └── ClientModEvents.java │ │ └── Itlt.java └── build.gradle ├── fabric ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper │ │ └── fabric.mod.json │ │ └── java │ │ └── ga │ │ └── ozli │ │ └── minecraftmods │ │ └── itlt │ │ ├── client │ │ └── ClientModEvents.java │ │ ├── Itlt.java │ │ └── platform │ │ └── FabricPlatformHelper.java └── build.gradle ├── .github └── ISSUE_TEMPLATE │ ├── something-else.md │ ├── 3_user-help.md │ ├── 2_suggestion.md │ ├── 4_dev_help.md │ └── 1_bug_report.md ├── .gitignore ├── .gitattributes ├── gradle.properties ├── LICENSE ├── settings.gradle ├── gradlew.bat ├── README.md ├── gradlew └── CHANGELOG.md /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zlepper/itlt/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /common/src/main/resources/META-INF/commonaccesstransformer.cfg: -------------------------------------------------------------------------------- 1 | public net.minecraft.client.Minecraft createTitle()Ljava/lang/String; 2 | -------------------------------------------------------------------------------- /common/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "${mod_name}", 4 | "pack_format": 8 5 | } 6 | } -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | public net.minecraft.client.Minecraft m_91270_()Ljava/lang/String; # createTitle 2 | -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/services/ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper: -------------------------------------------------------------------------------- 1 | ga.ozli.minecraftmods.itlt.platform.ForgePlatformHelper -------------------------------------------------------------------------------- /common/src/main/resources/itlt.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v2 named 2 | 3 | accessible method net/minecraft/client/Minecraft createTitle ()Ljava/lang/String; 4 | -------------------------------------------------------------------------------- /fabric/src/main/resources/META-INF/services/ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper: -------------------------------------------------------------------------------- 1 | ga.ozli.minecraftmods.itlt.platform.FabricPlatformHelper -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains classes that are shared across supported modding platforms 3 | */ 4 | package ga.ozli.minecraftmods.itlt.shared; 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/something-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Something else 3 | about: For stuff that doesn't fit in the other templates 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/platform/services/client/ClientPlatformHelper.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform.services.client; 2 | 3 | public interface ClientPlatformHelper { 4 | // todo 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea/* 15 | !.idea/scopes 16 | 17 | # gradle 18 | build 19 | .gradle 20 | 21 | # other 22 | eclipse 23 | run 24 | runs 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.bat text eol=crlf 3 | *.patch text eol=lf 4 | *.java text eol=lf 5 | *.gradle text eol=crlf 6 | *.png binary 7 | *.gif binary 8 | *.exe binary 9 | *.dll binary 10 | *.jar binary 11 | *.lzma binary 12 | *.zip binary 13 | *.pyd binary 14 | *.cfg text eol=lf 15 | *.jks binary -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /common/src/main/resources/itlt.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "ga.ozli.minecraftmods.itlt.shared.mixins", 5 | "refmap": "itlt.refmap.json", 6 | "compatibilityLevel": "JAVA_17", 7 | "client": ["WindowTitleMixin"], 8 | "injectors": { 9 | "defaultRequire": 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/platform/services/client/ClientServices.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform.services.client; 2 | 3 | import ga.ozli.minecraftmods.itlt.platform.Services; 4 | 5 | public final class ClientServices { 6 | public static final ClientPlatformHelper PLATFORM = Services.load(ClientPlatformHelper.class); 7 | 8 | private ClientServices() {} 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/Constants.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public final class Constants { 7 | public static final String MOD_ID = "itlt"; 8 | public static final String MOD_NAME = "It's The Little Things"; 9 | public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME); 10 | 11 | private Constants() {} 12 | } 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_user-help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: User help 3 | about: For players and modpack authors having trouble using itlt 4 | title: '' 5 | labels: help 6 | assignees: '' 7 | 8 | --- 9 | 10 | **How can we help?** 11 | Write your question here 12 | 13 | **Environment details** 14 | Please fill in what you know, skipping any parts you don't know. 15 | - Operating system (e.g. Windows 10): 16 | - Java (e.g. AdoptOpenJDK 8 HotSpot): 17 | - Mod version (e.g. 1.16.5-2.0.0): 18 | - Minecraft version (e.g. 1.16.5): 19 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/platform/services/IPlatformHelper.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform.services; 2 | 3 | import java.nio.file.Path; 4 | 5 | public interface IPlatformHelper { 6 | void addWarning(String message); 7 | 8 | Path getConfigDir(); 9 | 10 | enum PhysicalSide { 11 | CLIENT, 12 | SERVER; 13 | 14 | public boolean isClient() { 15 | return this == CLIENT; 16 | } 17 | } 18 | 19 | PhysicalSide getPhysicalSide(); 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggestion 3 | about: Suggest an idea or change for this project 4 | title: '' 5 | labels: suggestion 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Check if this has already been suggested first** 11 | Go to https://github.com/zlepper/itlt/issues?q=is%3Aopen+is%3Aissue+label%3Asuggestion to view a list of currently open suggestions. If you find one that's similar to yours, react on it with a thumbs up and leave a comment if you have any useful info to add. 12 | 13 | **What's your idea?** 14 | Write your idea/suggestion here 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4_dev_help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Dev help 3 | about: For developers having trouble working with itlt. For modpack authors, please use user help instead 4 | title: '' 5 | labels: dev help 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What branch are you trying to work with?** 11 | You can find a list of all branches here: https://github.com/zlepper/itlt/branches/all 12 | 13 | **How can we help?** 14 | Write your question here 15 | 16 | **Environment details** 17 | Please fill in what you know, skipping any parts you don't know. 18 | - Operating system (e.g. Windows 10): 19 | - IDE (e.g. IntelliJ 2021): 20 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/platform/Services.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform; 2 | 3 | import ga.ozli.minecraftmods.itlt.shared.Constants; 4 | import ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper; 5 | 6 | import java.util.ServiceLoader; 7 | 8 | public final class Services { 9 | public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class); 10 | 11 | public static T load(Class clazz) { 12 | T loadedService = ServiceLoader.load(clazz) 13 | .findFirst() 14 | .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); 15 | Constants.LOG.debug("Loaded {} for service {}", loadedService, clazz); 16 | return loadedService; 17 | } 18 | 19 | private Services() {} 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/mixins/WindowTitleMixin.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared.mixins; 2 | 3 | import ga.ozli.minecraftmods.itlt.shared.client.ClientUtils; 4 | import net.minecraft.client.Minecraft; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(Minecraft.class) 12 | public class WindowTitleMixin { 13 | @Shadow 14 | static Minecraft instance; 15 | 16 | @Inject(method = "updateTitle", at = @At("HEAD"), cancellable = true) 17 | private void itlt$updateTitle(CallbackInfo ci) { 18 | ClientUtils.setCustomWindowTitle(); 19 | ci.cancel(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "${forge_loader_version_range}" 3 | license = "${license}" 4 | issueTrackerURL = "https://github.com/zlepper/itlt/issues" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${version}" 9 | displayName = "${mod_name}" 10 | updateJSONURL = "https://forge.curseupdate.com/232791/itlt" 11 | displayURL = "https://www.curseforge.com/minecraft/mc-mods/its-the-little-things" 12 | logoFile = "${mod_id}.png" 13 | credits = "${credits}" 14 | authors = "${mod_author}" 15 | description = '''${description}''' 16 | 17 | [[dependencies.${mod_id}]] 18 | modId = "forge" 19 | mandatory = true 20 | versionRange = "[${forge_version},)" 21 | ordering = "NONE" 22 | side = "BOTH" 23 | 24 | [[dependencies.${mod_id}]] 25 | modId = "minecraft" 26 | mandatory = true 27 | versionRange = "${minecraft_version_range}" 28 | ordering = "NONE" 29 | side = "BOTH" 30 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${version}", 5 | "name": "${mod_name}", 6 | "description": "${description}", 7 | "authors": [ 8 | "${mod_author}" 9 | ], 10 | "contact": { 11 | "homepage": "https://www.curseforge.com/minecraft/mc-mods/its-the-little-things", 12 | "sources": "https://github.com/zlepper/itlt" 13 | }, 14 | "license": "${license}", 15 | "icon": "${mod_id}.png", 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "ga.ozli.minecraftmods.itlt.Itlt" 20 | ] 21 | }, 22 | "mixins": [ 23 | "itlt.mixins.json" 24 | ], 25 | "accessWidener": "itlt.accesswidener", 26 | "depends": { 27 | "fabricloader": ">=${fabric_loader_version}", 28 | "fabric-api": ">=${fabric_version}", 29 | "minecraft": "${minecraft_version}", 30 | "java": ">=${java_version}" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Important Notes: 2 | # Every field you add must be added to the root build.gradle expandProps map. 3 | 4 | # Project 5 | version=3.0.0-beta.3 6 | group=ga.ozli.minecraftmods.itlt 7 | java_version=21 8 | 9 | # Common 10 | minecraft_version=1.21.1 11 | mod_name=It's The Little Things 12 | mod_author=Paint_Ninja 13 | mod_id=itlt 14 | license=MIT 15 | credits= 16 | description=The description of your mod. \nAccepts multilines. 17 | minecraft_version_range=[1.21.1, 1.22) 18 | ## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here 19 | ## https://projects.neoforged.net/neoforged/neoform 20 | neo_form_version=1.21.1-20240808.144430 21 | # The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions 22 | parchment_minecraft=1.21.1 23 | parchment_version=2024.11.17 24 | 25 | # Fabric 26 | fabric_version=0.104.0+1.21.1 27 | fabric_loader_version=0.16.14 28 | 29 | # Forge 30 | forge_version=52.1.0 31 | forge_loader_version_range=[52,) 32 | 33 | # Gradle 34 | org.gradle.jvmargs=-Xmx3G 35 | org.gradle.daemon=false 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Zlepper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a crash or bug here 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Check if this has already been reported first** 11 | Go to https://github.com/zlepper/itlt/issues?q=is%3Aopen+is%3Aissue+label%3Abug to view a list of currently unresolved bugs. If you find one that matches your problem, react on it with a thumbs up and leave a comment if you have any useful info to add. 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the problem is. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. 19 | 2. 20 | 3. 21 | 4. 22 | (etc...) 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Environment details** 28 | Please fill in what you know, skip any parts you don't know. 29 | - Operating system (e.g. Windows 10): 30 | - Java (e.g. AdoptOpenJDK 8 HotSpot): 31 | - Mod version (e.g. 1.16.5-2.0.0): 32 | - Minecraft version (e.g. 1.16.5): 33 | 34 | **Logs and additional context** 35 | Add any other context about the problem here. 36 | 37 | It would be helpful if you could attach a debug.log and/or crash report. You can find the debug.log in the logs folder, where the resourcepacks folder is. 38 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-common' 3 | id 'net.neoforged.moddev' 4 | } 5 | 6 | neoForge { 7 | neoFormVersion = neo_form_version 8 | // Automatically enable AccessTransformers if the file exists 9 | def at = file('src/main/resources/META-INF/commonaccesstransformer.cfg') 10 | if (at.exists()) { 11 | accessTransformers.from(at.absolutePath) 12 | } 13 | parchment { 14 | minecraftVersion = parchment_minecraft 15 | mappingsVersion = parchment_version 16 | } 17 | } 18 | 19 | dependencies { 20 | compileOnly "org.spongepowered:mixin:0.8.7" 21 | } 22 | 23 | configurations { 24 | commonJava { 25 | canBeResolved = false 26 | canBeConsumed = true 27 | } 28 | commonResources { 29 | canBeResolved = false 30 | canBeConsumed = true 31 | } 32 | } 33 | 34 | artifacts { 35 | commonJava sourceSets.main.java.sourceDirectories.singleFile 36 | commonResources sourceSets.main.resources.sourceDirectories.singleFile 37 | } 38 | 39 | repositories { 40 | maven { 41 | name = "Fuzs Mod Resources" 42 | url = uri("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation "fuzs.forgeconfigapiport:forgeconfigapiport-common-forgeapi:21.1.3" 48 | } 49 | -------------------------------------------------------------------------------- /forge/src/main/java/ga/ozli/minecraftmods/itlt/platform/ForgePlatformHelper.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform; 2 | 3 | import ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper; 4 | import ga.ozli.minecraftmods.itlt.shared.Constants; 5 | import net.minecraftforge.fml.ModList; 6 | import net.minecraftforge.fml.ModLoader; 7 | import net.minecraftforge.fml.ModLoadingStage; 8 | import net.minecraftforge.fml.ModLoadingWarning; 9 | import net.minecraftforge.fml.loading.FMLEnvironment; 10 | import net.minecraftforge.fml.loading.FMLPaths; 11 | import net.minecraftforge.forgespi.language.IModInfo; 12 | 13 | import java.nio.file.Path; 14 | 15 | public final class ForgePlatformHelper implements IPlatformHelper { 16 | private static final ModLoader MOD_LOADER = ModLoader.get(); 17 | private static final ModList MOD_LIST = ModList.get(); 18 | private static final IModInfo ITLT_MOD_INFO = MOD_LIST.getModContainerById(Constants.MOD_ID).orElseThrow().getModInfo(); 19 | 20 | @Override 21 | public void addWarning(String message) { 22 | MOD_LOADER.addWarning(new ModLoadingWarning(ITLT_MOD_INFO, ModLoadingStage.COMMON_SETUP, message)); 23 | } 24 | 25 | @Override 26 | public Path getConfigDir() { 27 | return FMLPaths.CONFIGDIR.get(); 28 | } 29 | 30 | @Override 31 | public PhysicalSide getPhysicalSide() { 32 | return FMLEnvironment.dist.isClient() ? PhysicalSide.CLIENT : PhysicalSide.SERVER; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/Utils.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared; 2 | 3 | import oshi.SystemInfo; 4 | 5 | import java.lang.management.ManagementFactory; 6 | import java.util.Locale; 7 | 8 | public final class Utils { 9 | public static final SystemInfo SYSTEM_INFO = new SystemInfo(); 10 | 11 | public static class Memory { 12 | /** 13 | * Converts bytes to gigabytes, rounding to the nearest tenth (e.g.: 1.0, 1.1, 1.2...) 14 | */ 15 | private static float bytesToGigabytes(long bytes) { 16 | var megabytes = bytes >> 20; 17 | return Float.parseFloat(String.format(Locale.ROOT, "%.1f", megabytes / 1024.0f)); 18 | } 19 | 20 | /** 21 | * Gets the max amount of RAM allocated to the JVM in gigabytes, rounded to the nearest tenth 22 | */ 23 | public static float getJvmMax() { 24 | var memBean = ManagementFactory.getMemoryMXBean(); 25 | return bytesToGigabytes(memBean.getHeapMemoryUsage().getMax() + memBean.getNonHeapMemoryUsage().getMax()); 26 | } 27 | 28 | /** 29 | * Gets the amount of physical RAM this system has, rounded to the nearest tenth 30 | */ 31 | public static float getOsMax() { 32 | return bytesToGigabytes(SYSTEM_INFO.getHardware().getMemory().getTotal()); 33 | } 34 | 35 | private Memory() {} 36 | } 37 | 38 | private Utils() {} 39 | } 40 | -------------------------------------------------------------------------------- /forge/src/main/java/ga/ozli/minecraftmods/itlt/client/ClientModEvents.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.client; 2 | 3 | import ga.ozli.minecraftmods.itlt.platform.Services; 4 | import ga.ozli.minecraftmods.itlt.shared.client.ClientConfig; 5 | import ga.ozli.minecraftmods.itlt.shared.client.ClientUtils; 6 | import net.minecraftforge.fml.config.ModConfig; 7 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 8 | import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; 9 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 10 | 11 | public final class ClientModEvents { 12 | public static void onConstruct(FMLJavaModLoadingContext context) { 13 | context.registerConfig(ModConfig.Type.CLIENT, ClientConfig.SPEC); 14 | } 15 | 16 | public static void onClientSetup(FMLClientSetupEvent event) { 17 | ClientConfig.load(); 18 | ClientConfig.ready = true; 19 | 20 | // using enqueueWork to make sure this runs on the render thread 21 | event.enqueueWork(() -> { 22 | if (ClientConfig.Graphics.WRONG_GPU && ClientUtils.runningOnWrongGPU()) { 23 | Services.PLATFORM.addWarning("Running on wrong GPU"); 24 | } 25 | }); 26 | } 27 | 28 | public static void onLoadComplete(FMLLoadCompleteEvent event) { 29 | event.enqueueWork(ClientUtils::setCustomIcon); 30 | event.enqueueWork(ClientUtils::setCustomWindowTitle); 31 | } 32 | 33 | private ClientModEvents() {} 34 | } 35 | -------------------------------------------------------------------------------- /fabric/src/main/java/ga/ozli/minecraftmods/itlt/client/ClientModEvents.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.client; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import ga.ozli.minecraftmods.itlt.platform.Services; 5 | import ga.ozli.minecraftmods.itlt.shared.CommonConfig; 6 | import ga.ozli.minecraftmods.itlt.shared.client.ClientConfig; 7 | import ga.ozli.minecraftmods.itlt.shared.client.ClientUtils; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.gui.screens.Screen; 10 | import net.minecraft.client.gui.screens.TitleScreen; 11 | 12 | public final class ClientModEvents { 13 | private static boolean ranLoadComplete = false; 14 | 15 | public static void onClientSetup(Minecraft client) { 16 | RenderSystem.assertOnRenderThread(); 17 | 18 | ClientConfig.ready = true; 19 | 20 | if (ClientConfig.Graphics.WRONG_GPU && ClientUtils.runningOnWrongGPU()) { 21 | Services.PLATFORM.addWarning("Running on wrong GPU"); 22 | } 23 | } 24 | 25 | public static void onLoadComplete(Minecraft client, Screen screen, int scaledWidth, int scaledHeight) { 26 | if (ranLoadComplete) 27 | return; 28 | 29 | if (screen instanceof TitleScreen) { 30 | ranLoadComplete = true; 31 | 32 | ClientUtils.setCustomIcon(); 33 | 34 | if (CommonConfig.Java.Advanced.GC_ON_STARTUP) { 35 | System.gc(); 36 | } 37 | } 38 | } 39 | 40 | private ClientModEvents() {} 41 | } 42 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/CommonClass.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared; 2 | 3 | import ga.ozli.minecraftmods.itlt.platform.Services; 4 | 5 | public final class CommonClass { 6 | public static void checkJavaVersion() { 7 | byte currentJavaVer = (byte) Runtime.version().feature(); 8 | Constants.LOG.debug("currentJavaVer: {}", currentJavaVer); 9 | 10 | if (currentJavaVer < CommonConfig.Java.Version.MIN) { 11 | Services.PLATFORM.addWarning("Outdated Java"); 12 | } else if (CommonConfig.Java.Version.MAX != 0 && currentJavaVer > CommonConfig.Java.Version.MAX) { 13 | Services.PLATFORM.addWarning("Java too new"); 14 | } 15 | } 16 | 17 | public static void checkJavaMemory() { 18 | float currentJavaMaxMemGiB = Utils.Memory.getJvmMax(); 19 | Constants.LOG.debug("currentJavaMaxMemGiB: {}", currentJavaMaxMemGiB); 20 | 21 | if (currentJavaMaxMemGiB < CommonConfig.Java.Memory.MIN) { 22 | Services.PLATFORM.addWarning("Not enough memory"); 23 | } else if (CommonConfig.Java.Memory.MAX != 0 && currentJavaMaxMemGiB > CommonConfig.Java.Memory.MAX) { 24 | Services.PLATFORM.addWarning("Too much memory"); 25 | } else if (CommonConfig.Java.Memory.NEAR_MAX != 0 && currentJavaMaxMemGiB > (Utils.Memory.getOsMax() - CommonConfig.Java.Memory.NEAR_MAX)) { 26 | Services.PLATFORM.addWarning("Too much memory allocated for this machine"); 27 | } 28 | } 29 | 30 | private CommonClass() {} 31 | } 32 | -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-loader' 3 | id 'fabric-loom' 4 | } 5 | 6 | repositories { 7 | repositories { 8 | maven { 9 | name = "Fuzs Mod Resources" 10 | url = uri("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") 11 | } 12 | } 13 | } 14 | 15 | dependencies { 16 | minecraft "com.mojang:minecraft:${minecraft_version}" 17 | 18 | mappings loom.layered { 19 | officialMojangMappings() 20 | parchment "org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip" 21 | } 22 | 23 | modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" 24 | modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" 25 | 26 | modApi "fuzs.forgeconfigapiport:forgeconfigapiport-fabric:21.1.0" 27 | } 28 | 29 | loom { 30 | def aw = project(':common').file("src/main/resources/${mod_id}.accesswidener") 31 | if (aw.exists()) { 32 | accessWidenerPath = aw 33 | } 34 | 35 | mixin { 36 | defaultRefmapName = "${mod_id}.refmap.json" 37 | } 38 | 39 | runs { 40 | client { 41 | client() 42 | configName = "Fabric Client" 43 | ideConfigGenerated = true 44 | runDir = "runs/client" 45 | } 46 | server { 47 | server() 48 | configName = "Fabric Server" 49 | ideConfigGenerated = true 50 | runDir = "runs/server" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | exclusiveContent { 6 | forRepository { 7 | maven { 8 | name = 'Fabric' 9 | url = uri('https://maven.fabricmc.net') 10 | } 11 | } 12 | filter { 13 | includeGroup('net.fabricmc') 14 | includeGroup('fabric-loom') 15 | } 16 | } 17 | exclusiveContent { 18 | forRepository { 19 | maven { 20 | name = 'Sponge' 21 | url = uri('https://repo.spongepowered.org/repository/maven-public') 22 | } 23 | } 24 | filter { 25 | includeGroupAndSubgroups("org.spongepowered") 26 | } 27 | } 28 | exclusiveContent { 29 | forRepository { 30 | maven { 31 | name = 'Forge' 32 | url = uri('https://maven.minecraftforge.net') 33 | } 34 | } 35 | filter { 36 | includeGroupAndSubgroups('net.minecraftforge') 37 | } 38 | } 39 | } 40 | } 41 | 42 | plugins { 43 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' 44 | } 45 | 46 | // This should match the folder name of the project, or else IDEA may complain (see https://youtrack.jetbrains.com/issue/IDEA-317606) 47 | rootProject.name = 'itlt-v3' 48 | include('common') 49 | include('fabric') 50 | include('forge') 51 | -------------------------------------------------------------------------------- /fabric/src/main/java/ga/ozli/minecraftmods/itlt/Itlt.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt; 2 | 3 | import fuzs.forgeconfigapiport.fabric.api.forge.v4.ForgeConfigRegistry; 4 | import ga.ozli.minecraftmods.itlt.client.ClientModEvents; 5 | import ga.ozli.minecraftmods.itlt.shared.CommonClass; 6 | import ga.ozli.minecraftmods.itlt.shared.CommonConfig; 7 | import ga.ozli.minecraftmods.itlt.shared.Constants; 8 | import ga.ozli.minecraftmods.itlt.shared.client.ClientConfig; 9 | import net.fabricmc.api.EnvType; 10 | import net.fabricmc.api.ModInitializer; 11 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; 12 | import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; 13 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; 14 | import net.fabricmc.loader.api.FabricLoader; 15 | import net.neoforged.fml.config.ModConfig; 16 | 17 | public final class Itlt implements ModInitializer { 18 | @Override 19 | public void onInitialize() { 20 | ForgeConfigRegistry.INSTANCE.register(Constants.MOD_ID, ModConfig.Type.COMMON, CommonConfig.SPEC); 21 | 22 | // todo: crash callable 23 | 24 | CommonClass.checkJavaVersion(); 25 | CommonClass.checkJavaMemory(); 26 | 27 | if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { 28 | ForgeConfigRegistry.INSTANCE.register(Constants.MOD_ID, ModConfig.Type.CLIENT, ClientConfig.SPEC); 29 | 30 | ClientLifecycleEvents.CLIENT_STARTED.register(ClientModEvents::onClientSetup); 31 | ScreenEvents.BEFORE_INIT.register(ClientModEvents::onLoadComplete); 32 | } else { 33 | ServerLifecycleEvents.SERVER_STARTED.register(server -> { 34 | if (CommonConfig.Java.Advanced.GC_ON_STARTUP) { 35 | System.gc(); 36 | } 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fabric/src/main/java/ga/ozli/minecraftmods/itlt/platform/FabricPlatformHelper.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.platform; 2 | 3 | import ga.ozli.minecraftmods.itlt.platform.services.IPlatformHelper; 4 | import ga.ozli.minecraftmods.itlt.shared.Constants; 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; 7 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; 8 | import net.fabricmc.loader.api.FabricLoader; 9 | import net.minecraft.client.gui.screens.TitleScreen; 10 | 11 | import java.nio.file.Path; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public final class FabricPlatformHelper implements IPlatformHelper { 16 | private static final List WARNINGS = new ArrayList<>(); 17 | private static boolean registeredWarningHandler = false; 18 | 19 | @Override 20 | public void addWarning(String message) { 21 | WARNINGS.add(message); 22 | registerWarningHandlerIfNeeded(); 23 | } 24 | 25 | @Override 26 | public Path getConfigDir() { 27 | return FabricLoader.getInstance().getConfigDir(); 28 | } 29 | 30 | @Override 31 | public PhysicalSide getPhysicalSide() { 32 | return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT ? PhysicalSide.CLIENT : PhysicalSide.SERVER; 33 | } 34 | 35 | private static void registerWarningHandlerIfNeeded() { 36 | if (registeredWarningHandler) 37 | return; 38 | 39 | if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { 40 | // when on the main menu 41 | ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> { 42 | if (screen instanceof TitleScreen) { 43 | WARNINGS.forEach(Constants.LOG::warn); 44 | WARNINGS.clear(); 45 | } 46 | }); 47 | } else { 48 | ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> { 49 | WARNINGS.forEach(Constants.LOG::warn); 50 | WARNINGS.clear(); 51 | }); 52 | } 53 | 54 | registeredWarningHandler = true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /forge/src/main/java/ga/ozli/minecraftmods/itlt/Itlt.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt; 2 | 3 | import ga.ozli.minecraftmods.itlt.client.ClientModEvents; 4 | import ga.ozli.minecraftmods.itlt.shared.CommonClass; 5 | import ga.ozli.minecraftmods.itlt.shared.CommonConfig; 6 | import ga.ozli.minecraftmods.itlt.shared.Constants; 7 | import net.minecraftforge.event.server.ServerStartedEvent; 8 | import net.minecraftforge.eventbus.api.EventPriority; 9 | import net.minecraftforge.fml.CrashReportCallables; 10 | import net.minecraftforge.fml.common.Mod; 11 | import net.minecraftforge.fml.config.ModConfig; 12 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 13 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 14 | import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; 15 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 16 | import net.minecraftforge.fml.loading.FMLEnvironment; 17 | 18 | @Mod(Constants.MOD_ID) 19 | public record Itlt(FMLJavaModLoadingContext context) { 20 | public Itlt { 21 | context.registerConfig(ModConfig.Type.COMMON, CommonConfig.SPEC); 22 | 23 | var modBus = context.getModEventBus(); 24 | modBus.addListener(EventPriority.NORMAL, false, FMLCommonSetupEvent.class, this::onCommonSetup); 25 | 26 | if (FMLEnvironment.dist.isClient()) { 27 | ClientModEvents.onConstruct(context); 28 | modBus.addListener(EventPriority.NORMAL, false, FMLClientSetupEvent.class, ClientModEvents::onClientSetup); 29 | modBus.addListener(EventPriority.NORMAL, false, FMLLoadCompleteEvent.class, ClientModEvents::onLoadComplete); 30 | } 31 | } 32 | 33 | private void onCommonSetup(FMLCommonSetupEvent event) { 34 | CommonConfig.load(); 35 | 36 | CrashReportCallables.registerCrashCallable("Modpack details", CommonConfig.ModpackInfo.INSTANCE::toFriendlyString); 37 | 38 | CommonClass.checkJavaVersion(); 39 | CommonClass.checkJavaMemory(); 40 | 41 | if (CommonConfig.Java.Advanced.GC_ON_STARTUP) { 42 | var modBus = context.getModEventBus(); 43 | if (FMLEnvironment.dist.isClient()) { 44 | modBus.addListener(EventPriority.MONITOR, false, FMLLoadCompleteEvent.class, e -> System.gc()); 45 | } else { 46 | modBus.addListener(EventPriority.MONITOR, false, ServerStartedEvent.class, e -> System.gc()); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/client/ClientConfig.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared.client; 2 | 3 | import ga.ozli.minecraftmods.itlt.shared.CommonConfig; 4 | import net.minecraftforge.common.ForgeConfigSpec; 5 | 6 | import java.util.Collections; 7 | 8 | public final class ClientConfig { 9 | private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder() { 10 | @Override 11 | public ForgeConfigSpec.Builder push(String groupName) { 12 | return super.push(Collections.singletonList(groupName)); 13 | } 14 | }; 15 | 16 | private static final ForgeConfigSpec.BooleanValue WRONG_GPU; 17 | 18 | private static final ForgeConfigSpec.ConfigValue WINDOW_TITLE_FORMAT; 19 | 20 | public static final ForgeConfigSpec SPEC; 21 | 22 | public static volatile boolean ready = false; 23 | 24 | static { 25 | BUILDER.push("Graphics"); { 26 | WRONG_GPU = BUILDER 27 | .comment( 28 | "", 29 | " Sometimes players accidentally run the game on integrated graphics instead of their dedicated GPU, which severely hurts performance.", 30 | " Turn this on to warn the player when they are using integrated graphics but have a dedicated GPU installed.", 31 | " Don't worry - they won't be warned if they only have integrated graphics, because there is no dedicated GPU to switch to." 32 | ) 33 | .define("wrongGPU", true); 34 | } BUILDER.pop(); 35 | 36 | BUILDER.push("Display"); { 37 | WINDOW_TITLE_FORMAT = BUILDER 38 | .define("windowTitleFormat", "%mc - %modpackName %modpackVersion"); 39 | } BUILDER.pop(); 40 | 41 | SPEC = BUILDER.build(); 42 | } 43 | 44 | public static final class Graphics { 45 | public static final boolean WRONG_GPU = ClientConfig.WRONG_GPU.get(); 46 | 47 | private static void load() {} 48 | 49 | private Graphics() {} 50 | } 51 | 52 | public static final class Display { 53 | public static final String WINDOW_TITLE; 54 | 55 | static { 56 | var windowTitleFormat = ClientConfig.WINDOW_TITLE_FORMAT.get(); 57 | if (!windowTitleFormat.contains("%mc")) 58 | windowTitleFormat = "%mc - " + windowTitleFormat; 59 | 60 | WINDOW_TITLE = windowTitleFormat 61 | .replaceFirst("%modpackName", CommonConfig.ModpackInfo.INSTANCE.name()) 62 | .replaceFirst("%modpackVersion", CommonConfig.ModpackInfo.INSTANCE.version()) 63 | .trim(); 64 | } 65 | 66 | private static void load() {} 67 | 68 | private Display() {} 69 | } 70 | 71 | public static void load() { 72 | Graphics.load(); 73 | Display.load(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /forge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-loader' 3 | id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' 4 | id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' 5 | } 6 | 7 | base.archivesName = "${mod_name}-forge-${minecraft_version}" 8 | 9 | minecraft { 10 | mappings channel: 'official', version: minecraft_version 11 | 12 | copyIdeResources = true //Calls processResources when in dev 13 | 14 | reobf = false // Forge 1.20.6+ uses official mappings at runtime, so we shouldn't reobf from official to SRG 15 | 16 | // Automatically enable forge AccessTransformers if the file exists 17 | // This location is hardcoded in Forge and can not be changed. 18 | // https://github.com/MinecraftForge/MinecraftForge/blob/be1698bb1554f9c8fa2f58e32b9ab70bc4385e60/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java#L123 19 | // Forge still uses SRG names during compile time, so we cannot use the common AT's 20 | def at = file('src/main/resources/META-INF/accesstransformer.cfg') 21 | if (at.exists()) { 22 | accessTransformer = at 23 | } 24 | 25 | runs { 26 | client { 27 | workingDirectory file('runs/client') 28 | ideaModule "${rootProject.name}.${project.name}.main" 29 | taskName 'Client' 30 | property 'forge.logging.console.level', 'debug' 31 | mods { 32 | modClientRun { 33 | source sourceSets.main 34 | } 35 | } 36 | } 37 | 38 | server { 39 | workingDirectory file('runs/server') 40 | ideaModule "${rootProject.name}.${project.name}.main" 41 | taskName 'Server' 42 | mods { 43 | modServerRun { 44 | source sourceSets.main 45 | } 46 | } 47 | } 48 | 49 | data { 50 | workingDirectory file('runs/data') 51 | ideaModule "${rootProject.name}.${project.name}.main" 52 | args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') 53 | taskName 'Data' 54 | mods { 55 | modDataRun { 56 | source sourceSets.main 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | sourceSets.main.resources.srcDir 'src/generated/resources' 64 | 65 | dependencies { 66 | minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" 67 | 68 | implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } 69 | } 70 | 71 | mixin { 72 | config "${mod_id}.mixins.json" 73 | } 74 | 75 | tasks.named('jar', Jar) { 76 | manifest { 77 | attributes['MixinConfigs'] = "${mod_id}.mixins.json" 78 | } 79 | } 80 | 81 | publishing { 82 | publications { 83 | mavenJava(MavenPublication) { 84 | fg.component(it) 85 | } 86 | } 87 | } 88 | 89 | sourceSets.each { 90 | def dir = layout.buildDirectory.dir("sourcesSets/$it.name") 91 | it.output.resourcesDir = dir 92 | it.java.destinationDirectory = dir 93 | } 94 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/client/ClientUtils.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared.client; 2 | 3 | import com.mojang.blaze3d.platform.NativeImage; 4 | import com.mojang.blaze3d.systems.RenderSystem; 5 | import ga.ozli.minecraftmods.itlt.platform.Services; 6 | import ga.ozli.minecraftmods.itlt.shared.Constants; 7 | import ga.ozli.minecraftmods.itlt.shared.mixins.WindowTitleMixin; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.server.packs.resources.IoSupplier; 10 | import org.jetbrains.annotations.Nullable; 11 | import org.lwjgl.glfw.GLFW; 12 | import org.lwjgl.glfw.GLFWImage; 13 | import org.lwjgl.system.MemoryStack; 14 | import org.lwjgl.system.MemoryUtil; 15 | 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.nio.ByteBuffer; 19 | import java.nio.file.Files; 20 | import java.nio.file.Path; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Locale; 24 | 25 | public final class ClientUtils { 26 | private static final Minecraft MC = Minecraft.getInstance(); 27 | 28 | /** 29 | * Checks if MC is running on the wrong GPU (i.e. integrated graphics despite dedicated being available) 30 | * @return true if so, false if not or unsure 31 | */ 32 | public static boolean runningOnWrongGPU() { 33 | var allGpus = ExtendedGraphicsCard.getAll(); 34 | if (allGpus.size() == 1) 35 | return false; // only one GPU, so can't be wrong 36 | 37 | @Nullable var currentGpu = ExtendedGraphicsCard.getCurrent(allGpus); 38 | if (currentGpu == null) 39 | return false; // can't determine current GPU 40 | 41 | return currentGpu.isIntegrated(); 42 | } 43 | 44 | public static void setCustomIcon() { 45 | if (Minecraft.ON_OSX) 46 | return; // todo: macOS support 47 | 48 | try { 49 | var icons = ClientUtils.getIcons(); 50 | if (icons.isEmpty()) 51 | return; 52 | 53 | ClientUtils.setWindowIcon(icons); 54 | } catch (IOException e) { 55 | Constants.LOG.error("Failed to set window icon: {}", e.toString()); 56 | } 57 | } 58 | 59 | /** @see WindowTitleMixin */ 60 | public static void setCustomWindowTitle() { 61 | if (!ClientConfig.ready) return; 62 | MC.getWindow().setTitle(ClientConfig.Display.WINDOW_TITLE.replaceFirst("%mc", MC.createTitle())); 63 | } 64 | 65 | private static List> getIcons() throws IOException { 66 | // look for icons in the itlt folder 67 | var itltFolder = Services.PLATFORM.getConfigDir().resolve("itlt"); 68 | 69 | List iconCandidates; 70 | try (var files = Files.list(itltFolder)) { 71 | iconCandidates = files.filter(ClientUtils::isIcon).toList(); 72 | } 73 | 74 | if (iconCandidates.isEmpty()) { 75 | Constants.LOG.debug("No icons found in {}", itltFolder); 76 | return List.of(); 77 | } 78 | 79 | Constants.LOG.debug("Found icons: {}", iconCandidates); 80 | 81 | // for now, let's just use the first PNG we find 82 | // todo: support ICO and ICNS files 83 | return iconCandidates.stream() 84 | .filter(path -> getFileExtension(path).equals("png")) 85 | .map(IoSupplier::create) 86 | .limit(1) 87 | .toList(); 88 | 89 | // switch (iconCandidates.size()) { 90 | // case 0 -> Constants.LOG.debug("No icons found in {}", itltFolder); 91 | // case 1 -> Constants.LOG.debug("Found icon: {}", iconCandidates.getFirst()); 92 | // default -> { 93 | // Constants.LOG.debug("Found multiple icons: {}", iconCandidates); 94 | // 95 | // // if we have an ico or icns file, use that and ignore the rest 96 | // var icoOrIcns = iconCandidates.stream() 97 | // .filter(path -> getFileExtension(path).equals("ico") || getFileExtension(path).equals("icns")) 98 | // .findFirst(); 99 | // 100 | // if (icoOrIcns.isPresent()) { 101 | // // yay, we have an ico/icns file! let's extract all the different sizes from it 102 | // var iconPath = icoOrIcns.get(); 103 | // // todo 104 | // } else { 105 | // // no ico/icns file, do we have pngs? 106 | // } 107 | // } 108 | // } 109 | } 110 | 111 | private static boolean isIcon(Path iconPath) { 112 | return switch (getFileExtension(iconPath)) { 113 | case "png", "ico", "icns" -> true; 114 | default -> false; 115 | }; 116 | } 117 | 118 | private static String getFileExtension(Path path) { 119 | var fileName = path.getFileName().toString(); 120 | var lastDot = fileName.lastIndexOf('.'); 121 | return lastDot == -1 ? "" : fileName.substring(lastDot + 1).toLowerCase(Locale.ROOT); 122 | } 123 | 124 | private static void setWindowIcon(List> icons) throws IOException { 125 | RenderSystem.assertOnRenderThread(); 126 | 127 | int platform = GLFW.glfwGetPlatform(); 128 | switch (platform) { 129 | case GLFW.GLFW_PLATFORM_WIN32, GLFW.GLFW_PLATFORM_X11 -> { 130 | var setIcons = new ArrayList(icons.size()); 131 | 132 | try (var memoryStack = MemoryStack.stackPush()) { 133 | GLFWImage.Buffer buffer = GLFWImage.malloc(icons.size(), memoryStack); 134 | 135 | for (int i = 0; i < icons.size(); i++) { 136 | try (var nativeimage = NativeImage.read(icons.get(i).get())) { 137 | ByteBuffer bytebuffer = MemoryUtil.memAlloc(nativeimage.getWidth() * nativeimage.getHeight() * 4); 138 | setIcons.add(bytebuffer); 139 | bytebuffer.asIntBuffer().put(nativeimage.getPixelsRGBA()); 140 | buffer.position(i); 141 | buffer.width(nativeimage.getWidth()); 142 | buffer.height(nativeimage.getHeight()); 143 | buffer.pixels(bytebuffer); 144 | } 145 | } 146 | 147 | GLFW.glfwSetWindowIcon(MC.getWindow().getWindow(), buffer.position(0)); 148 | } finally { 149 | setIcons.forEach(MemoryUtil::memFree); 150 | } 151 | } 152 | // todo: macOS (aka GLFW.GLFW_PLATFORM_COCOA) 153 | case GLFW.GLFW_PLATFORM_COCOA, GLFW.GLFW_PLATFORM_WAYLAND, GLFW.GLFW_PLATFORM_NULL -> {} 154 | default -> Constants.LOG.warn("Not setting icon for unrecognized platform: {}", platform); 155 | } 156 | } 157 | 158 | private ClientUtils() {} 159 | } 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![It's the little things logo](https://zlepper.github.io/itlt/docs/logo/logo-long-githubdark.png)](https://www.curseforge.com/minecraft/mc-mods/its-the-little-things) 2 | 3 | [![](http://cf.way2muchnoise.eu/short_232791_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/its-the-little-things) [![](http://cf.way2muchnoise.eu/versions/For%20MC_232791_all.svg?1.19)](https://www.curseforge.com/minecraft/mc-mods/its-the-little-things/files) 4 | 5 | ## About itlt 6 | 7 | It's the little things that make all the difference, the finishing touches to your modpack. :) 8 | 9 | ### 📂 Download 10 | 11 | Available for download at CurseForge: https://www.curseforge.com/minecraft/mc-mods/its-the-little-things 12 | 13 | ## 🎮 Players and modpack authors 14 | 15 | ### ❓ Help 16 | 17 | If you need help using or troubleshooting itlt, you can open a support ticket by [clicking here](https://github.com/zlepper/itlt/issues/new?labels=help&template=3_user-help.md). The wiki may also be helpful: https://github.com/zlepper/itlt/wiki 18 | 19 | ### 🐛 Problems and bugs 20 | 21 | If you're having a problem with itlt crashing or being buggy, please [file a new bug report](https://github.com/zlepper/itlt/issues/new?labels=bug&template=1_bug_report.md) and I'll look into it. 22 | 23 | ### 💡 Suggestions 24 | 25 | If you have an idea or suggestion for itlt, I'd love to hear it! 26 | 27 | Check out [this issues page](https://github.com/zlepper/itlt/issues?q=is%3Aissue+is%3Aopen+label%3Asuggestion) to see if it's already been suggested and leave a thumbs up on things you would like to see implemented. To make a new suggestion, [click here](https://github.com/zlepper/itlt/issues/new?labels=suggestion&template=2_suggestion.md). 28 | 29 | ## 🛠 Contributors and developers 30 | 31 | Please refer to the [Technical Documentation](TechnicalDocumentation.md) - it provides a technical overview, troubleshooting, to-do lists and various details about how stuff works and how to add or change stuff. 32 | 33 | ### ❓ Help 34 | 35 | If you need a hand working with itlt, ping me (@Paint_Ninja) in **#squirrels** on [Forgecord](https://discord.gg/UvedJ9m). Remember to bare their rules in mind. Alternatively, [open a dev support ticket](https://github.com/PaintNinja/issue-template-test/issues/new?labels=dev+help&template=4_dev_help.md) and I'll get back to you when I can. 36 | 37 | ### 📝 Notes 38 | 39 | - All branches are actively maintained, but don't worry! For contributing, you only need to submit a PR to one branch (of your choice) and I'll handle porting to the rest after merging your PR. 40 | - If you want to add support for a Minecraft version that doesn't already have a branch, open a dev support ticket and I'll make the branch for you so you can make your PR. 41 | - There are two versions of this mod 42 | - v2 which is the latest version that has being rewritten from the ground up. All work on new features is being done in v2. 43 | - v1 is the original mod which has been backported to legacy Minecraft versions and gets maintained with minor bugfixes and changes. 44 | 45 | ### Branches 46 | 47 | #### Current 48 | 49 | Work for the latest supported Minecraft version is done on the "master" branch, however mod update checking always uses named branches to ensure reliability during a switchover to a newer MC version. When 1.18 comes out, master is merged onto 1.17 and 1.18 work goes on master. Until then, the 1.16 branch serves as a placeholder for update checking. 50 | 51 | | Branch | Minecraft version | Mod version | ForgeGradle version | Gradle version | 52 | |-------------------------------------------------------------------------------|-------------------------|-------------|----------------------------------|----------------| 53 | | master (you're here) | 1.20.x | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 54 | | [1.19.4](https://github.com/zlepper/itlt/tree/1.19.4) | 1.19.4 | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 55 | | [1.19.3](https://github.com/zlepper/itlt/tree/1.19.3) | 1.19.3 | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 56 | | [1.19/1.19.1/1.19.2](https://github.com/zlepper/itlt/tree/1.19/1.19.1/1.19.2) | 1.19, 1.19.1 and 1.19.2 | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 57 | | [1.18](https://github.com/zlepper/itlt/tree/1.18) | 1.18.x | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 58 | | [1.17](https://github.com/zlepper/itlt/tree/1.17) | 1.17.1 | **v2** | ForgeGradle 5.1 | Gradle 7.5.1 | 59 | | [1.16](https://github.com/zlepper/itlt/tree/1.16) | 1.16.x | **v2** | ForgeGradle 4.1 | Gradle 6.9 | 60 | | [1.15](https://github.com/zlepper/itlt/tree/1.15) | 1.15.x | **v2** | ForgeGradle 4.1 | Gradle 6.9 | 61 | | [1.14](https://github.com/zlepper/itlt/tree/1.14) | 1.14.x | **v2** | ForgeGradle 4.1 | Gradle 6.9 | 62 | | [1.13](https://github.com/zlepper/itlt/tree/1.13) | 1.13.2 | **v2** | ForgeGradle 4.1 | Gradle 6.9 | 63 | | [1.12](https://github.com/zlepper/itlt/tree/1.12) | 1.12.2 | v1 | ForgeGradle 4.1 | Gradle 6.9 | 64 | | [1.11](https://github.com/zlepper/itlt/tree/1.11) | 1.11.x | v1 | ForgeGradle 2.2.1 | Gradle 4.10.3 | 65 | | [1.10](https://github.com/zlepper/itlt/tree/1.10) | 1.10.x | v1 | ForgeGradle 2.2.1 | Gradle 4.10.3 | 66 | | [1.9](https://github.com/zlepper/itlt/tree/1.9) | 1.9.x | v1 | ForgeGradle 2.1.1 | Gradle 4.10.3 | 67 | | [1.8.8/1.8.9](https://github.com/zlepper/itlt/tree/1.8.8/1.8.9) | 1.8.8 and 1.8.9 | v1 | ForgeGradle 2.1.1 | Gradle 4.10.3 | 68 | | [1.8](https://github.com/zlepper/itlt/tree/1.8) | 1.8.0 | v1 | ForgeGradle 2.0-SNAPSHOT-aa67375 | Gradle 4.7 | 69 | | [1.7](https://github.com/zlepper/itlt/tree/1.7) | 1.7.x | v1 | ForgeGradle 1.2.1 | Gradle 4.4.1 | 70 | | [1.6](https://github.com/zlepper/itlt/tree/1.6) | 1.6.x | v1 | ForgeGradle 1.0 | Gradle 3.0 | 71 | | [1.4.6/1.4.7](https://github.com/zlepper/itlt/tree/1.4.6/1.4.7) | 1.4.6 and 1.4.7 | v1 | ForgeGradle 4.1.legacy-SNAPSHOT | Gradle 6.9 | 72 | 73 | #### Legacy 74 | 75 | These are still maintained, but are worked on much less often due to being harder to setup and work with in general. 76 | 77 | I've provided `Instructions.md` and some additional files in each of these branches to help. I strongly recommend you read the instructions if you're not already familiar with the process, otherwise you're going end up spending a while troubleshooting. These Python scripts no longer work out of the box like they used to - they need a bit of manual setup and a specific environment to work in. RetroGradle aims to eventually port these MC versions to use ForgeGradle 4 but it's a long way off - possibly years from now. 78 | 79 | | Branch | Minecraft version | Mod version | Dev toolchain | Python version | 80 | |-----------------------------------------------------------------|-------------------|-------------|----------------------------------------------------------|----------------| 81 | | [1.5](https://github.com/zlepper/itlt/tree/1.5) | 1.5.x | v1 | Forge Src 7.8.1.738(?) + MCP 7.51 scripts + Manual steps | Python 2.7.3 | 82 | | [1.4.4/1.4.5](https://github.com/zlepper/itlt/tree/1.4.4/1.4.5) | 1.4.4 and 1.4.5 | v1 | Forge Src 6.4.2.448(?) + MCP 7.23 scripts + Manual steps | Python 2.7.3 | 83 | | [1.3.2](https://github.com/zlepper/itlt/tree/1.3.2) | 1.3.2 | v1 | Forge Src 4.3.5.318(?) + MCP 7.2 scripts + Manual steps | Python 2.7.2 | 84 | | [1.2.5](https://github.com/zlepper/itlt/tree/1.2.5) | 1.2.5 | v1 | Forge Src 3.4.9.171(?) + MCP 6.2 scripts + Manual steps | Python 2.7.2 | 85 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/client/ExtendedGraphicsCard.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared.client; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import ga.ozli.minecraftmods.itlt.shared.Utils; 5 | import org.jetbrains.annotations.Nullable; 6 | import oshi.hardware.GraphicsCard; 7 | 8 | import java.util.List; 9 | import java.util.Locale; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import java.util.stream.Collectors; 13 | 14 | import static ga.ozli.minecraftmods.itlt.shared.client.ExtendedGraphicsCard.GraphicsBrand.*; 15 | 16 | record ExtendedGraphicsCard(GraphicsCard delegate) implements GraphicsCard { 17 | public enum GraphicsBrand { 18 | AMD, 19 | NVIDIA, 20 | INTEL, 21 | UNKNOWN; 22 | 23 | private static final String[] AMD_API_STRINGS = { "AMD ", "Radeon", "ATI Technologies", "0x1002" }; 24 | 25 | public static GraphicsBrand getCurrent() { 26 | var apiDescription = RenderSystem.getApiDescription(); 27 | 28 | if (apiDescription.contains("Intel ")) 29 | return INTEL; 30 | 31 | if (isAMD(apiDescription)) 32 | return AMD; 33 | 34 | if (apiDescription.toLowerCase(Locale.ROOT).contains("nvidia")) 35 | return NVIDIA; 36 | 37 | return UNKNOWN; 38 | } 39 | 40 | private static boolean isAMD(String apiDescription) { 41 | for (String apiStr : AMD_API_STRINGS) { 42 | if (apiDescription.contains(apiStr)) { 43 | return true; 44 | } 45 | } 46 | 47 | return false; 48 | } 49 | } 50 | 51 | @Override 52 | public String getName() { 53 | return delegate.getName(); 54 | } 55 | 56 | @Override 57 | public String getDeviceId() { 58 | return delegate.getDeviceId(); 59 | } 60 | 61 | @Override 62 | public String getVendor() { 63 | return delegate.getVendor(); 64 | } 65 | 66 | @Override 67 | public String getVersionInfo() { 68 | return delegate.getVersionInfo(); 69 | } 70 | 71 | @Override 72 | public long getVRam() { 73 | return delegate.getVRam(); 74 | } 75 | 76 | public GraphicsBrand getBrand() { 77 | if (getVendor().contains("Intel") || getVendor().contains("8086")) 78 | return INTEL; 79 | 80 | if (getName().contains("AMD") || getVendor().contains("0x1002")) 81 | return AMD; 82 | 83 | if (getVendor().toLowerCase(Locale.ROOT).contains("nvidia")) 84 | return NVIDIA; 85 | 86 | return UNKNOWN; 87 | } 88 | 89 | public boolean isIntegrated() { 90 | return switch (getBrand()) { 91 | case INTEL -> KnownGPUs.Intel.isIntegrated(getDeviceId()); 92 | case AMD -> KnownGPUs.AMD.isIntegrated(getDeviceId()); 93 | default -> false; // if NVIDIA or unknown, assume it's not integrated 94 | }; 95 | } 96 | 97 | @Nullable 98 | public static ExtendedGraphicsCard getCurrent(Map> candidates) { 99 | return getCurrent(candidates, GraphicsBrand.getCurrent()); 100 | } 101 | 102 | @Nullable 103 | public static ExtendedGraphicsCard getCurrent(Map> candidates, GraphicsBrand currentBrand) { 104 | var filteredCandidates = candidates.get(currentBrand); 105 | if (filteredCandidates == null || filteredCandidates.isEmpty()) 106 | return null; // the current brand isn't in the candidates somehow!? 107 | 108 | if (filteredCandidates.size() > 1) 109 | return null; // can't tell which of the filtered candidates are running as they're all the same brand 110 | 111 | return filteredCandidates.getFirst(); 112 | } 113 | 114 | public static Map> getAll() { 115 | return Utils.SYSTEM_INFO.getHardware().getGraphicsCards().stream() 116 | .map(ExtendedGraphicsCard::new) 117 | .collect(Collectors.groupingBy(ExtendedGraphicsCard::getBrand)); 118 | } 119 | 120 | private static final class KnownGPUs { 121 | private static final class Intel { 122 | /** 123 | * @link Wikipedia list of Intel graphics processing units 124 | * @link Intel graphics hardware devices table 125 | * @link PCI ID repository 126 | */ 127 | private static final Set KNOWN_INTEL_IGPUS = Set.of( 128 | "A780", // Desktop Raptor Lake UHD Graphics 770 129 | 130 | // Mobile Alder Lake 131 | "46A6", "46A8", "46AA", // Intel Xe Graphics 132 | "46A3", "46B3", "46C3", // UHD Graphics 133 | 134 | // Desktop Alder Lake 135 | "4680", "4690", // UHD Graphics 770 136 | "4692", // UHD Graphics 730 137 | "4693", // UHD Graphics 710 138 | 139 | // Mobile Tiger Lake 140 | "9A49", "9A40", // Intel Xe Graphics 141 | "9A78", // UHD Graphics 142 | 143 | // Desktop Rocket Lake 144 | "4C8A", // UHD Graphics 750 145 | "4C8B", // UHD Graphics 730 146 | 147 | // Mobile Ice Lake 148 | "8A53", "8A52", "8A51", "8A5A", "8A5C", // Iris Plus Graphics 149 | "8A56", "8A58", // UHD Graphics 150 | 151 | // Mobile Coffee Lake 152 | "3EA5", // Iris Plus Graphics 655 153 | "3EA6", // Iris Plus Graphics 645 154 | "3E9B", // UHD Graphics 630 155 | 156 | // Desktop Coffee Lake 157 | "3E92", "3E91", // UHD Graphics 630 158 | "3E93", // UHD Graphics 610 159 | 160 | // Mobile Kaby Lake 161 | "5927", // Iris Plus Graphics 650 162 | "5926", // Iris Plus Graphics 640 163 | "591B", // HD Graphics 630 164 | "5917", // UHD Graphics 620 165 | "5916", // HD Graphics 620 166 | "591E", // HD Graphics 615 167 | "5906", // HD Graphics 610 168 | 169 | // Desktop Kaby Lake 170 | "5912", // HD Graphics 630 171 | "5902", // HD Graphics 610 172 | 173 | // Mobile and Desktop, Gemini Lake and Gemini Lake Refresh 174 | "3184", // UHD Graphics 605 175 | "3185", // UHD Graphics 600 176 | 177 | // Mobile and Desktop Skylake 178 | "193B", // Iris Pro Graphics 580 179 | "1927", // Iris Graphics 550 180 | "1926", // Iris Graphics 540 181 | "1912", "191B", // HD Graphics 530 182 | "1916", // HD Graphics 520 183 | "191E", // HD Graphics 515 184 | "1902", "1906", // HD Graphics 510 185 | 186 | // Mobile and Desktop Apollo Lake 187 | "5A84", // HD Graphics 505 188 | "5A85", // HD Graphics 500 189 | 190 | // Other UHD Graphics 191 | "A78B", "A78A", "A789", "A788", "A783", "A782", "A781", // Raptor Lake-S 192 | "4682", "4688", "468A", "468B", // Alder Lake-S 193 | "46D0", "46D1", "46D2", // Alder Lake-N 194 | "4626", "4628", "462A", "46A0", "46A1", "46A2", "46B0", "46B1", "46B2", "46C0", "46C1", "46C2", // Alder Lake 195 | "4C90", "4C9A", "4C8C", "4C80", // Rocket Lake 196 | "4E71", "4E61", "4E57", "4E55", "4E51", // Jasper Lake 197 | "9A59", "9A60", "9A68", "9A70", "9AC0", "9AC9", "9AD9", "9AF8" // Tiger Lake 198 | ); 199 | 200 | private static boolean isIntegrated(String deviceId) { 201 | return KNOWN_INTEL_IGPUS.contains(deviceId); 202 | } 203 | 204 | private Intel() {} 205 | } 206 | 207 | private static final class AMD { 208 | /** 209 | * In no particular order. 210 | * @link PCI ID repository 211 | * @link DeviceHunt listing 212 | */ 213 | private static final Set KNOWN_AMD_IGPUS = Set.of( 214 | "1638", // Cezanne 215 | "15d8", // Picasso 216 | "15dd", // Raven Ridge 217 | "1636", // Renoir 218 | "164c", // Lucienne 219 | "164d", "1681", // Rembrandt 220 | "164e", // Raphael 221 | "15bf", "164f", // Phoenix 222 | "15c8", // Phoenix 2 223 | "15e7", // Barcelo 224 | "1506", // Mendocino 225 | "150e" // Strix 226 | ); 227 | 228 | private static boolean isIntegrated(String deviceID) { 229 | return KNOWN_AMD_IGPUS.contains(deviceID); 230 | } 231 | 232 | private AMD() {} 233 | } 234 | 235 | private KnownGPUs() {} 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | org.gradle.wrapper.GradleWrapperMain \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /common/src/main/java/ga/ozli/minecraftmods/itlt/shared/CommonConfig.java: -------------------------------------------------------------------------------- 1 | package ga.ozli.minecraftmods.itlt.shared; 2 | 3 | import net.minecraftforge.common.ForgeConfigSpec; 4 | 5 | import java.util.Collections; 6 | 7 | public final class CommonConfig { 8 | private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder() { 9 | // ITLT uses nested push/pop calls to create a hierarchy of config options rather than using a dot-separated string. 10 | // This method is overridden to skip the path parsing and directly push the group name as a singleton list for performance reasons. 11 | @Override 12 | public ForgeConfigSpec.Builder push(String groupName) { 13 | return super.push(Collections.singletonList(groupName)); 14 | } 15 | }; 16 | 17 | private static final ForgeConfigSpec.ConfigValue JAVA_VER_GUIDE; 18 | private static final ForgeConfigSpec.ByteValue MIN_JAVA_WARN; 19 | private static final ForgeConfigSpec.ByteValue MAX_JAVA_WARN; 20 | 21 | private static final ForgeConfigSpec.ConfigValue MEM_GUIDE; 22 | private static final ForgeConfigSpec.FloatValue MIN_MEM_WARN; 23 | private static final ForgeConfigSpec.FloatValue MAX_MEM_WARN; 24 | private static final ForgeConfigSpec.FloatValue NEAR_MAX_MEM_WARN; 25 | 26 | private static final ForgeConfigSpec.BooleanValue GC_ON_STARTUP; 27 | 28 | static final ForgeConfigSpec.ConfigValue PACK_NAME; 29 | static final ForgeConfigSpec.ConfigValue PACK_VER; 30 | static final ForgeConfigSpec.ConfigValue PACK_SUPPORT_URL; 31 | 32 | public static final ForgeConfigSpec SPEC; 33 | 34 | static { 35 | BUILDER.push("Java"); { 36 | 37 | BUILDER.push("Version"); { 38 | JAVA_VER_GUIDE = BUILDER.define("guideUrl", ""); 39 | MIN_JAVA_WARN = BUILDER 40 | .comment( 41 | " ", 42 | " The minimum recommended Java version to run the modpack.", 43 | " Newer versions may have better performance, but some mods may break.", 44 | " Depending on the launcher being used, it may be difficult/annoying for users to change the Java version used for starting your modpack.", 45 | " ", 46 | " The default is Java 21, which is the minimum version required by Minecraft 1.20.5+." 47 | ) 48 | .defineInRange("min", (byte) 21, (byte) 21, (byte) 127); 49 | MAX_JAVA_WARN = BUILDER 50 | .comment( 51 | " ", 52 | " The maximum recommended Java version to run the modpack.", 53 | " If you know that a mod in your pack is buggy with a certain Java version, you can warn the user against using too new Java here.", 54 | " ", 55 | " To disable this warning, set the value to 0." 56 | ) 57 | .defineInRange("max", (byte) 0, (byte) 0, (byte) 127); 58 | } BUILDER.pop(); 59 | 60 | BUILDER.push("Memory"); { 61 | MEM_GUIDE = BUILDER.define("guideUrl", ""); 62 | MIN_MEM_WARN = BUILDER 63 | .comment( 64 | " ", 65 | " If you know that your modpack fails to load into a world if the player allocates too little memory, you can set a minimum memory warning here.", 66 | " Do not set the minimum too high, as allocating too much memory can hurt performance and prevent the game from starting on low-end PCs.", 67 | " ", 68 | " To disable this warning, set the value to 0." 69 | ) 70 | .defineInRange("min", 1f, 0f, 1024f); 71 | MAX_MEM_WARN = BUILDER 72 | .comment( 73 | "", 74 | " Allocating too much memory can hurt performance and cause lag spikes - you can set a max memory warning to help prevent that.", 75 | " ", 76 | " To disable this warning, set the value to 0." 77 | ) 78 | .defineInRange("max", 0f, 0f, 1024f); 79 | NEAR_MAX_MEM_WARN = BUILDER 80 | .comment( 81 | " ", 82 | " Some players may allocate more memory than they have in their PC, or allocate all of it without leaving any spare for the OS, drivers and other apps.", 83 | " This can severely hurt performance because it makes the game fight with everything else for resources and spills over from RAM to the much slower swap space.", 84 | " You can set a warning when the allocated memory is near the maximum available memory to help prevent that.", 85 | " The default is to warn when there's less than 1GB spare memory left.", 86 | " ", 87 | " To disable this warning, set the value to 0." 88 | ) 89 | .defineInRange("nearMax", 1f, 0f, 3f); 90 | } BUILDER.pop(); 91 | 92 | BUILDER.push("Advanced"); { 93 | GC_ON_STARTUP = BUILDER 94 | .comment( 95 | " ", 96 | " Run an explicit full GC after the game has finished loading.", 97 | " This can help reduce initial memory usage, but causes a one-time brief pause after the game loads.", 98 | " ", 99 | " Warning: This option has no effect if the -XX:+DisableExplicitGC JVM arg is present." 100 | ) 101 | .define("enableExplicitGC", true); 102 | } BUILDER.pop(); 103 | 104 | } BUILDER.pop(); 105 | 106 | BUILDER.push("ModpackInfo"); { 107 | PACK_NAME = BUILDER 108 | .comment( 109 | " ", 110 | " The name of your modpack" 111 | ) 112 | .define("name", ""); 113 | PACK_VER = BUILDER 114 | .comment( 115 | " ", 116 | " The version of your modpack" 117 | ) 118 | .define("version", ""); 119 | PACK_SUPPORT_URL = BUILDER 120 | .comment( 121 | " ", 122 | " The URL to your modpack's support page for players to get help with crashes" 123 | ) 124 | .define("supportUrl", "https://discord.minecraftforge.net"); 125 | } BUILDER.pop(); 126 | 127 | SPEC = BUILDER.build(); 128 | } 129 | 130 | public static final class Java { 131 | static final class Version { 132 | static final String GUIDE = CommonConfig.JAVA_VER_GUIDE.get(); 133 | static final byte MIN = CommonConfig.MIN_JAVA_WARN.get(); 134 | static final byte MAX = CommonConfig.MAX_JAVA_WARN.get(); 135 | 136 | // ensure the class is loaded so that the static fields are initialised at this point 137 | private static void load() {} 138 | 139 | private Version() {} 140 | } 141 | 142 | static final class Memory { 143 | static final String GUIDE = CommonConfig.MEM_GUIDE.get(); 144 | static final float MIN = CommonConfig.MIN_MEM_WARN.get(); 145 | static final float MAX = CommonConfig.MAX_MEM_WARN.get(); 146 | static final float NEAR_MAX = CommonConfig.NEAR_MAX_MEM_WARN.get(); 147 | 148 | private static void load() {} 149 | 150 | private Memory() {} 151 | } 152 | 153 | public static final class Advanced { 154 | public static final boolean GC_ON_STARTUP = CommonConfig.GC_ON_STARTUP.get(); 155 | 156 | private static void load() {} 157 | 158 | private Advanced() {} 159 | } 160 | 161 | private Java() {} 162 | } 163 | 164 | public record ModpackInfo(String name, String version, String supportUrl) { 165 | public static final ModpackInfo INSTANCE = new ModpackInfo( 166 | CommonConfig.PACK_NAME.get(), CommonConfig.PACK_VER.get(), CommonConfig.PACK_SUPPORT_URL.get() 167 | ); 168 | 169 | public ModpackInfo { 170 | assert name != null; 171 | assert version != null; 172 | assert supportUrl != null; 173 | 174 | if (name.isBlank()) 175 | name = "Unknown"; 176 | 177 | if (version.isBlank()) 178 | version = "Unknown"; 179 | 180 | if (supportUrl.isBlank()) 181 | throw new IllegalArgumentException("Modpack support URL cannot be blank"); 182 | } 183 | 184 | public String toFriendlyString() { 185 | return """ 186 | 187 | \t\tName: %s 188 | \t\tVersion: %s 189 | \t\tSupport URL: %s 190 | """.stripTrailing().formatted(name, version, supportUrl); 191 | } 192 | } 193 | 194 | public static void load() { 195 | Java.Version.load(); 196 | Java.Memory.load(); 197 | Java.Advanced.load(); 198 | } 199 | 200 | private CommonConfig() {} 201 | } 202 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | [![It's the little things logo](https://github.com/zlepper/itlt/raw/gh-pages/docs/logo/logo-long-githubdark.png)](https://www.curseforge.com/minecraft/mc-mods/its-the-little-things) 2 | 3 | # Changelog 4 | 5 | # v2.2.1 6 | 7 | ## MC 1.20-specific changes 8 | 9 | - Thanks to Ferri_Arnus for the initial port to 1.20 and 1.20.1 10 | 11 | ## Bug fixes 12 | 13 | - New approach to changing the window icon which should improve macOS compatibility 14 | 15 | # v2.2.0 16 | 17 | ## New features 18 | 19 | ### Simplified config 20 | 21 | Some config options have been removed or changed to simplify the config and make things easier. **Existing config files will be automatically migrated to the new format on launch, so you don't need to worry about losing your settings.** 22 | 23 | - A new option has been added called `modpackName` in the `[Display.General]` section 24 | - If left blank, itlt will attempt to automatically detect the name of the modpack you're using from supported launchers 25 | - Otherwise the name you set will be used 26 | - `%autoName` has been renamed to `%modpackName`, but the old placeholder variable will still work for now 27 | 28 | # v2.1.5 29 | 30 | ## Bug fixes 31 | 32 | - Fixed a bug that caused itlt to wrongly get blamed for other mod's crashes in certain situations ([#34](https://github.com/zlepper/itlt/issues/34), [#39](https://github.com/zlepper/itlt/issues/39)) 33 | 34 | # v2.1.4 35 | 36 | ## Bug fixes 37 | 38 | - Hotfix: Fixed a migration error due to a silly programming mistake again in v2.1.3. 39 | 40 | ## Other changes 41 | 42 | - The amount of variables I need to change for migration to work properly has been significantly reduced, hopefully preventing the bug from happening again. 43 | - All the changes from v2.1.3 (see below) 44 | 45 | # v2.1.3 46 | 47 | ## MC 1.19-specific changes 48 | 49 | - itlt now supports Forge 41.1.0+ and MC 1.19.1 50 | - Removed usage of a deprecated GLFWImage method 51 | 52 | ## MC 1.19-specific bug fixes 53 | 54 | - Fixed a bug where the mod would claim to be incompatible if you looked in the datapacks 55 | 56 | ## Other changes 57 | 58 | - Minor performance improvements 59 | 60 | # v2.1.2 61 | 62 | ## MC 1.19-specific changes 63 | 64 | - itlt now supports MC 1.19 65 | 66 | ## Bug fixes 67 | 68 | - Hotfix: Fixed an issue causing config files to wrongly be deleted due to a programming mistake in v2.1.1. 69 | - A backup is made on first load with v2.1.1. You can restore the backup by deleting `itlt-client.toml` in the config folder and changing `itlt-client.toml.bak` to `itlt-client.toml` 70 | - Once the backup is restored, update itlt to v2.1.2 to fix the issue. 71 | - It is recommended that all v2.1.1 users update to v2.1.2 if they want a non-default config take effect. 72 | - All the fixes from v2.1.1 (see below) 73 | 74 | # v2.1.1 75 | 76 | ## MC 1.18-specific bug fixes 77 | 78 | - Fixed a typo seen when running the itlt jar directly where it wrongly tells you to put the jar in the mods folder of a Minecraft Forge 1.17.x instance (it should say 1.18.x for the 1.18.x jar) 79 | 80 | ## Bug fixes 81 | 82 | - Fixed a crash on launch if the game is launched near the root of a drive. ([#38](https://github.com/zlepper/itlt/issues/38)) 83 | - Fixed an issue causing launcher integration features not working on some Linux systems ([#37](https://github.com/zlepper/itlt/issues/37)) 84 | 85 | # v2.1.0 86 | 87 | ## MC 1.18-specific changes 88 | 89 | - itlt now supports MC 1.18 90 | - Gradle 7.3.1 91 | - Default config for min Java version matches MC 1.18's min requirement of Java 17 92 | 93 | ## Bug fixes 94 | 95 | - Fixed a bug in config generation that caused every group to be inside the Java group. 96 | - Configs made older versions that had this bug will be automatically fixed to work on this version. 97 | - Fixed a startup crash on some macOS systems 98 | 99 | ## New features 100 | 101 | ### Welcome screen 102 | 103 | You can now optionally show a screen on first launch. This could be used to show a changelog, give advice to new users or provide links to your pack's social media for example. 104 | 105 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.1.0/WelcomeScreen.png) 106 | 107 | The welcome screen supports MC formatting codes for different colours and styles, headings, clickable links, word-wrapping and scrolling. Simply enable the config option and edit the `config/itlt/welcome.txt` file. 108 | 109 | Note: This feature is experimental. It is stable, but may change in a future release. I will mention in the changelog if this feature receives any breaking changes. 110 | 111 | ### Improved custom window title feature 112 | 113 | Vanilla changes the window title based on what you're doing (e.g. it mentions "Singleplayer" when playing a singleplayer world). 114 | 115 | Before v2.1.0, itlt didn't support this feature and kept the window title static. v2.1.0 now supports this feature. 116 | 117 | ### Config migration 118 | 119 | itlt now automatically migrates old configs to the version you're running and makes a backup, allowing you to update to a version of itlt containing otherwise breaking config changes without needing to fix your config manually. The backup is deleted on second launch. 120 | 121 | This basically means that if the config format changes in newer versions, itlt will automatically convert your previous config file to work with the latest version, preserving your existing preferences where possible. 122 | 123 | This feature currently supports migrating from v2.0.0/v2.0.1 to v2.1.0. Support for migrating configs from older versions is currently unimplemented. 124 | 125 | ### Improved config validation 126 | 127 | To help troubleshooting mistakes with your config, the mod now logs an error if you set requirements that are impossible to meet (e.g. requiring that the user simultaneously uses at least Java 11 but not newer than Java 8). 128 | 129 | Additionally, ranges have been added to the min/max memory config options to prevent them being accidentally set to a negative value. 130 | 131 | ## Other changes 132 | 133 | - Minor performance improvements 134 | - itlt will no longer log when it can't find the config/itlt/ folder but successfully created it for you - instead, it will now only let you know if you need to manually do it yourself 135 | - Fixed a couple of typos in the config 136 | 137 | # v2.0.1 138 | 139 | This release adds support for MC 1.17.1 and fixes a couple of bugs that caused crash on launch issues for some users as well as minor performance improvements and other changes. 140 | 141 | ## MC 1.17-specific changes 142 | 143 | - itlt now supports MC 1.17.1 144 | - Using a JS coremod instead of Mixin for custom window title handling 145 | - Updated config defaults to reflect MC 1.17's new Java requirements 146 | - ForgeGradle 5.1, Gradle 7.2, MojMap 147 | - The code now takes full advantage of modern Java features when available and support for modern Java has been improved 148 | - Improved support for Java 17 149 | 150 | ## Bug fixes 151 | 152 | - Fixed a startup crash on system locales that separate decimal points with commas (#24) 153 | - The "Enhanced Vanilla Icon" logic no longer unnecessarily runs when a valid custom icon is provided 154 | 155 | ## Other changes 156 | 157 | - Icon handling has been made more robust and can now continue to use an icon when it contains corrupt/invalid embedded images, as long as at least one embedded image is okay 158 | - Improved debug logging and error messages for icon handling 159 | 160 | # v2.0.0 161 | 162 | With v2 of itlt, everything has been written from the ground-up with a goal on being the best at the specific little things it does. 163 | 164 | ## Breaking changes 165 | 166 | Everything's changed so this release is not compatible with existing v1 configs. The default behaviour of auto-detecting the modpack's icon and title is still in place. 167 | 168 | ## New features 169 | 170 | ### Full multi-lingual support 171 | 172 | All features in itlt v2 should support different languages, allowing it to be localised to your desired language rather than being forced to read English. This includes features outside of the game, such as the warning and requirements system 173 | 174 | ### Improved launcher integration 175 | 176 | itlt now uses a more modular system for launcher detection and integration and supports many different launchers. While v1 supported the Technic Launcher, v2 also supports MultiMC, Curse Client, FTB App and the Forge Dev Env. 177 | 178 | ### Warning and requirements system 179 | 180 | You can now let people know when they haven't allocated enough RAM at launch with a helpful pop-up. Or if they're using the wrong Java version or architecture. Or if they're allocating waaaay too much RAM, or a combination of the above. 181 | 182 | These things can be set multiple times separately as warnings and requirements - where warnings are considered recommendations, requirements are considered "this modpack won't start or will crash if not met". 183 | 184 | Using the new launcher integration features, the guides are tailored to the launcher your players are using, making it easier to find what settings to change to get your pack running. 185 | 186 | There's also now the ability for your users to "Don't ask again" for specific warnings. This remembers a user's preference to ignore a specific warning but still have warnings they haven't seen before to be shown. 187 | 188 | Here's a couple of examples of what your users could see, depending on how you configure it: 189 | 190 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/WantsMoreMemory.png) 191 | 192 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/NeedsNewerJava.png) 193 | 194 | Here's a list of supported warnings (shown as "Wants") and requirements (shown as "Needs") in v2.0.0: 195 | 196 | - NeedsJava64bit 197 | - WantsJava64bit 198 | - NeedsMoreMemory 199 | - WantsMoreMemory 200 | - NeedsLessMemory 201 | - WantsLessMemory 202 | - NeedsNewerJava 203 | - WantsNewerJava 204 | - NeedsOlderJava 205 | - WantsOlderJava 206 | 207 | ### Overhauled custom icon handling 208 | 209 | The new icon handling system supports ICO, ICNS and PNG files as well as launcher integration for automatically detecting and using your modpack's icon from its platform listing. 210 | 211 | With Hi-DPI and multi-size ICO and ICNS support, your modpack's icon can look crisp at any screen resolution and size. When an exact size isn't available, the closest one is resized and used automatically. 212 | 213 | To see this in action, check out [this single ICO file](https://github.com/zlepper/itlt/blob/gh-pages/docs/guides/itlt/icon.ico) automatically display different sizes depending on the resolution scale: 214 | 215 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/100%25.png) 216 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/125%25.png) 217 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/150%25.png) 218 | 219 | More scales: [200%](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/200%25.png), [300%](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/300%25.png), [400%](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/400%25.png), [500%](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/500%25.png) 220 | 221 | #### __Enhanced Vanilla Icon__ 222 | 223 | This feature uses the new icon handling system for the Vanilla icon on Windows and Linux, boosting its maximum resolution from 32px² to 48px² 224 | 225 | Vanilla: 226 | 227 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/400%25-vanilla.png) 228 | 229 | itlt: 230 | 231 | ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/400%25-enhanced-vanilla.png) 232 | 233 | ### New custom window title system 234 | 235 | Mojang have politely asked people to not completely replace existing branding, effectively taking credit for their work. 236 | 237 | With v2, itlt respects this with new defaults and string interpolation techniques. This brings a few benefits: 238 | 239 | - Easier for others to troubleshoot your modpack by knowing what Minecraft version it's based on 240 | - The ability to vaguely tell what the player's doing by the window title (e.g. `ModpackName - Minecraft* 1.16.5 (Multiplayer)`) 241 | - Ability to use launcher integration and static titles simultaneously, allowing for you to name your pack "myPack" in the launcher and have the title show up as "myPack v2" for example when launching v2 of your pack, "myPack v3" when launching v3, etc... 242 | 243 | ### Multiple entries in custom server list 244 | 245 | You can now pre-install more than one server entry to the Multiplayer menu without overwriting or removing player-added ones when updating the modpack. You can now also force the use of a server-provided resourcepack for specific preloaded server entries. 246 | 247 | ### Explicit GC 248 | 249 | For advanced users looking to squeeze the most performance out of their game and have a reasonably good understanding of garbage collection, this feature allows you to explicitly request a GC during known points of gameplay that do not require immediate responsiveness when opened, such as pausing the game or sleeping in a bed. 250 | 251 | This feature requires both Xms and Xmx to be set the same for it to be beneficial, ideally with the `-XX:+AlwaysPreTouch` JVM arg. You must *not* use the `-XX:+DisableExplicitGC` otherwise this feature will not work at all. Due to these important requirements that have to be manually added by users, the explicit GC feature is off by default. 252 | 253 | ### Update checker support 254 | 255 | itlt now supports the Forge update checker and will show available updates on the Mods button if enabled. 256 | 257 | ### Categorised, detailed config 258 | 259 | All config options are categorised and have detailed comments to group similar settings together and to help you understand what every setting does. The wiki fills in additional information you may need that the config doesn't cover in enough depth. 260 | 261 | ### Miscellaneous improvements 262 | 263 | - The itlt entry in the mods menu now features the itlt logo. 264 | - When using a modern version of Java, itlt will automatically use more efficient methods with graceful fallbacks to Java 8 code. The same jar still works on Java 8 as usual. 265 | - Pop-up windows now attempt to use a more system-native design, with custom code for handling showing native Windows iconography rather than Swing's bundled Windows 7 icons 266 | - Pop-up windows are ran in a separate process so that they can persist after a game crash and to avoid causing crash-on-launch issues on older Mac OSX 267 | - If you run the itlt jar directly, you'll now get this message both in the console output and as a GUI dialogue box: 268 | - ![](https://zlepper.github.io/itlt/docs/changelogs/v2.0.0/install-dialogue.png) 269 | 270 | ## Other changes 271 | 272 | ### New logo 273 | 274 | Heavily inspired by the old logo, the new one uses the same fontface but with more visually consistent sizing and spacing. The new logo also supports transparency and different variations. 275 | 276 | You can see the old logo here: https://github.com/zlepper/itlt/blob/gh-pages/docs/logo/old-logo.jpeg 277 | 278 | And the new logo and all of its variations here: https://github.com/zlepper/itlt/tree/gh-pages/docs/logo 279 | 280 | ### Technical documentation 281 | 282 | For developers, a document providing a technical overview, Q&A, todo lists and more is now available. 283 | 284 | You can view it by going to the branch you want to work on and looking at the TechnicalDocumentation.md file. 285 | 286 | ### Issue templates 287 | 288 | Pre-filled templates to choose from when filing a new issue that automatically labels your issue for you. 289 | --------------------------------------------------------------------------------