mirror of
				https://github.com/chylex/Minecraft-Window-Title.git
				synced 2025-10-31 12:17:18 +01:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			2a17b46a1d
			...
			1.12/older
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cc06491313 | |||
| bba8a16afb | 
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | |||||||
| * text=auto eol=lf |  | ||||||
							
								
								
									
										1
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | |||||||
| ko_fi: chylex |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								.github/README/screenshot.png
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/README/screenshot.png
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 245 KiB | 
							
								
								
									
										31
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,30 +1 @@ | |||||||
| # gradle | Build/ | ||||||
|  |  | ||||||
| .gradle/ |  | ||||||
| build/ |  | ||||||
| out/ |  | ||||||
| classes/ |  | ||||||
|  |  | ||||||
| # eclipse |  | ||||||
|  |  | ||||||
| *.launch |  | ||||||
|  |  | ||||||
| # idea |  | ||||||
|  |  | ||||||
| .idea/ |  | ||||||
| *.iml |  | ||||||
| *.ipr |  | ||||||
| *.iws |  | ||||||
|  |  | ||||||
| # vscode |  | ||||||
|  |  | ||||||
| .settings/ |  | ||||||
| .vscode/ |  | ||||||
| bin/ |  | ||||||
| .classpath |  | ||||||
| .project |  | ||||||
|  |  | ||||||
| # fabric |  | ||||||
|  |  | ||||||
| run/ |  | ||||||
| logs/ |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project version="4"> |  | ||||||
|   <component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8"> |  | ||||||
|     <file url="PROJECT" charset="UTF-8" /> |  | ||||||
|   </component> |  | ||||||
| </project> |  | ||||||
							
								
								
									
										18
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,18 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project version="4"> |  | ||||||
|   <component name="GradleMigrationSettings" migrationVersion="1" /> |  | ||||||
|   <component name="GradleSettings"> |  | ||||||
|     <option name="linkedExternalProjectsSettings"> |  | ||||||
|       <GradleProjectSettings> |  | ||||||
|         <option name="externalProjectPath" value="$PROJECT_DIR$" /> |  | ||||||
|         <option name="modules"> |  | ||||||
|           <set> |  | ||||||
|             <option value="$PROJECT_DIR$" /> |  | ||||||
|             <option value="$PROJECT_DIR$/Fabric" /> |  | ||||||
|             <option value="$PROJECT_DIR$/NeoForge" /> |  | ||||||
|           </set> |  | ||||||
|         </option> |  | ||||||
|       </GradleProjectSettings> |  | ||||||
|     </option> |  | ||||||
|   </component> |  | ||||||
| </project> |  | ||||||
							
								
								
									
										11
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,11 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project version="4"> |  | ||||||
|   <component name="GitSharedSettings"> |  | ||||||
|     <option name="FORCE_PUSH_PROHIBITED_PATTERNS"> |  | ||||||
|       <list /> |  | ||||||
|     </option> |  | ||||||
|   </component> |  | ||||||
|   <component name="VcsDirectoryMappings"> |  | ||||||
|     <mapping directory="" vcs="Git" /> |  | ||||||
|   </component> |  | ||||||
| </project> |  | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| import net.fabricmc.loom.configuration.ide.RunConfigSettings |  | ||||||
| import org.gradle.jvm.tasks.Jar |  | ||||||
|  |  | ||||||
| val modId: String by project |  | ||||||
| val modSides: String by project |  | ||||||
| val minecraftVersion: String by project |  | ||||||
| val fabricVersion: String by project |  | ||||||
|  |  | ||||||
| plugins { |  | ||||||
| 	id("fabric-loom") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| dependencies { |  | ||||||
| 	minecraft("com.mojang:minecraft:$minecraftVersion") |  | ||||||
| 	modImplementation("net.fabricmc:fabric-loader:$fabricVersion") |  | ||||||
| 	mappings(loom.officialMojangMappings()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| loom { |  | ||||||
| 	runs { |  | ||||||
| 		val runJvmArgs: Set<String> by project |  | ||||||
| 		 |  | ||||||
| 		configureEach { |  | ||||||
| 			runDir("../run") |  | ||||||
| 			vmArgs(runJvmArgs) |  | ||||||
| 			ideConfigGenerated(true) |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		fun side(name: String, configure: RunConfigSettings.() -> Unit) { |  | ||||||
| 			if (modSides == "both" || modSides == name) { |  | ||||||
| 				named(name, configure) |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				findByName(name)?.let(::remove) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		side("client") { |  | ||||||
| 			configName = "Fabric Client" |  | ||||||
| 			client() |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		side("server") { |  | ||||||
| 			configName = "Fabric Server" |  | ||||||
| 			server() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	mixin { |  | ||||||
| 		defaultRefmapName.set("$modId.refmap.json") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| tasks.processResources { |  | ||||||
| 	filesMatching("fabric.mod.json") { |  | ||||||
| 		expand(inputs.properties) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| tasks.register<Jar>("uncompressedRemapJar") { |  | ||||||
| 	group = "fabric" |  | ||||||
| 	 |  | ||||||
| 	from(tasks.remapJar.map { it.outputs.files.map(::zipTree) }) |  | ||||||
| 	 |  | ||||||
| 	archiveClassifier.set("uncompressed") |  | ||||||
| 	entryCompression = ZipEntryCompression.STORED // Reduces size of multiloader jar. |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| package chylex.customwindowtitle.fabric; |  | ||||||
|  |  | ||||||
| import chylex.customwindowtitle.TitleChanger; |  | ||||||
| import chylex.customwindowtitle.TitleConfig; |  | ||||||
| import chylex.customwindowtitle.data.CommonTokenData; |  | ||||||
| import net.fabricmc.api.ClientModInitializer; |  | ||||||
| import net.fabricmc.loader.api.FabricLoader; |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
|  |  | ||||||
| public class CustomWindowTitle implements ClientModInitializer { |  | ||||||
| 	private final TitleConfig config; |  | ||||||
| 	 |  | ||||||
| 	public CustomWindowTitle() { |  | ||||||
| 		config = TitleConfig.load(FabricLoader.getInstance().getConfigDir().toAbsolutePath().toString()); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	@Override |  | ||||||
| 	public void onInitializeClient() { |  | ||||||
| 		CommonTokenData.register(new TokenProvider()); |  | ||||||
| 		Minecraft.getInstance().execute(() -> TitleChanger.setTitle(config)); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| package chylex.customwindowtitle.fabric; |  | ||||||
|  |  | ||||||
| import chylex.customwindowtitle.TokenException; |  | ||||||
| import chylex.customwindowtitle.data.CommonTokenProvider; |  | ||||||
| import net.fabricmc.loader.api.FabricLoader; |  | ||||||
|  |  | ||||||
| final class TokenProvider implements CommonTokenProvider { |  | ||||||
| 	@Override |  | ||||||
| 	public String getModVersion(final String modId) { |  | ||||||
| 		return FabricLoader.getInstance() |  | ||||||
| 			.getModContainer(modId) |  | ||||||
| 			.orElseThrow(() -> new TokenException("mod info for '" + modId + "' not found")) |  | ||||||
| 			.getMetadata() |  | ||||||
| 			.getVersion() |  | ||||||
| 			.getFriendlyString(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| { |  | ||||||
|   "schemaVersion": 1, |  | ||||||
|   "id": "${id}", |  | ||||||
|   "name": "${name}", |  | ||||||
|   "description": "${description}", |  | ||||||
|   "version": "${version}", |  | ||||||
|   "license": "${license}", |  | ||||||
|    |  | ||||||
|   "authors": [ |  | ||||||
|     "${author}" |  | ||||||
|   ], |  | ||||||
|    |  | ||||||
|   "contact": { |  | ||||||
|     "homepage": "https://chylex.com", |  | ||||||
|     "issues": "${issuesURL}", |  | ||||||
|     "sources": "${sourcesURL}" |  | ||||||
|   }, |  | ||||||
|    |  | ||||||
|   "environment": "${sidesForFabric}", |  | ||||||
|   "entrypoints": { |  | ||||||
|     "client": [ |  | ||||||
|       "chylex.customwindowtitle.fabric.CustomWindowTitle" |  | ||||||
|     ] |  | ||||||
|   }, |  | ||||||
|    |  | ||||||
|   "mixins": [{ |  | ||||||
|     "config": "${id}.mixins.json", |  | ||||||
|     "environment": "${sidesForFabric}" |  | ||||||
|   }], |  | ||||||
|    |  | ||||||
|   "depends": { |  | ||||||
|     "fabricloader": ">=${minimumFabricVersion}", |  | ||||||
|     "minecraft": ">=${minimumMinecraftVersion}" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										25
									
								
								Forge/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Forge/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | # eclipse | ||||||
|  | bin | ||||||
|  | *.launch | ||||||
|  | .settings | ||||||
|  | .metadata | ||||||
|  | .classpath | ||||||
|  | .project | ||||||
|  |  | ||||||
|  | # idea | ||||||
|  | out | ||||||
|  | *.ipr | ||||||
|  | *.iws | ||||||
|  | *.iml | ||||||
|  | .idea | ||||||
|  |  | ||||||
|  | # gradle | ||||||
|  | build | ||||||
|  | .gradle | ||||||
|  |  | ||||||
|  | # other | ||||||
|  | eclipse | ||||||
|  | run | ||||||
|  |  | ||||||
|  | # Files from Forge MDK | ||||||
|  | forge*changelog.txt | ||||||
							
								
								
									
										39
									
								
								Forge/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Forge/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | buildscript{ | ||||||
|  |     repositories{ | ||||||
|  |         maven{ url = 'https://files.minecraftforge.net/maven' } | ||||||
|  |         jcenter() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dependencies{ | ||||||
|  |         classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | apply plugin: 'net.minecraftforge.gradle.forge' | ||||||
|  |  | ||||||
|  | def mcversion = "1.12.2" | ||||||
|  | def forgeversion = "14.23.5.2847" | ||||||
|  |  | ||||||
|  | def metaName = "Custom Window Title" | ||||||
|  | def metaVersion = "1.0.0" | ||||||
|  |  | ||||||
|  | group = 'chylex.customwindowtitle.forge' | ||||||
|  | version = metaVersion | ||||||
|  | archivesBaseName = metaName.replaceAll('\\s', '') | ||||||
|  |  | ||||||
|  | sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' | ||||||
|  |  | ||||||
|  | minecraft{ | ||||||
|  |     version = mcversion + '-' + forgeversion | ||||||
|  |     runDir = "run" | ||||||
|  |     mappings = "snapshot_20180814" | ||||||
|  |     makeObfSourceJar = false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | jar{ | ||||||
|  |     archiveName = archivesBaseName + '-Legacy-v' + version + '.jar' | ||||||
|  |  | ||||||
|  |     from('../'){ | ||||||
|  |         include 'LICENSE' | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								Forge/gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Forge/gradle.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. | ||||||
|  | # This is required to provide enough memory for the Minecraft decompilation process. | ||||||
|  | org.gradle.jvmargs=-Xmx3G | ||||||
|  | org.gradle.daemon=false | ||||||
							
								
								
									
										
											BIN
										
									
								
								Forge/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Forge/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,7 +1,5 @@ | |||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip |  | ||||||
| networkTimeout=10000 |  | ||||||
| validateDistributionUrl=true |  | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
|  | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip | ||||||
							
								
								
									
										172
									
								
								Forge/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Forge/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  |  | ||||||
|  | ############################################################################## | ||||||
|  | ## | ||||||
|  | ##  Gradle start up script for UN*X | ||||||
|  | ## | ||||||
|  | ############################################################################## | ||||||
|  |  | ||||||
|  | # Attempt to set APP_HOME | ||||||
|  | # Resolve links: $0 may be a link | ||||||
|  | PRG="$0" | ||||||
|  | # Need this for relative symlinks. | ||||||
|  | while [ -h "$PRG" ] ; do | ||||||
|  |     ls=`ls -ld "$PRG"` | ||||||
|  |     link=`expr "$ls" : '.*-> \(.*\)$'` | ||||||
|  |     if expr "$link" : '/.*' > /dev/null; then | ||||||
|  |         PRG="$link" | ||||||
|  |     else | ||||||
|  |         PRG=`dirname "$PRG"`"/$link" | ||||||
|  |     fi | ||||||
|  | done | ||||||
|  | SAVED="`pwd`" | ||||||
|  | cd "`dirname \"$PRG\"`/" >/dev/null | ||||||
|  | APP_HOME="`pwd -P`" | ||||||
|  | cd "$SAVED" >/dev/null | ||||||
|  |  | ||||||
|  | APP_NAME="Gradle" | ||||||
|  | APP_BASE_NAME=`basename "$0"` | ||||||
|  |  | ||||||
|  | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
|  | DEFAULT_JVM_OPTS="" | ||||||
|  |  | ||||||
|  | # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||||
|  | MAX_FD="maximum" | ||||||
|  |  | ||||||
|  | warn () { | ||||||
|  |     echo "$*" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | die () { | ||||||
|  |     echo | ||||||
|  |     echo "$*" | ||||||
|  |     echo | ||||||
|  |     exit 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # OS specific support (must be 'true' or 'false'). | ||||||
|  | cygwin=false | ||||||
|  | msys=false | ||||||
|  | darwin=false | ||||||
|  | nonstop=false | ||||||
|  | case "`uname`" in | ||||||
|  |   CYGWIN* ) | ||||||
|  |     cygwin=true | ||||||
|  |     ;; | ||||||
|  |   Darwin* ) | ||||||
|  |     darwin=true | ||||||
|  |     ;; | ||||||
|  |   MINGW* ) | ||||||
|  |     msys=true | ||||||
|  |     ;; | ||||||
|  |   NONSTOP* ) | ||||||
|  |     nonstop=true | ||||||
|  |     ;; | ||||||
|  | esac | ||||||
|  |  | ||||||
|  | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||||
|  |  | ||||||
|  | # Determine the Java command to use to start the JVM. | ||||||
|  | if [ -n "$JAVA_HOME" ] ; then | ||||||
|  |     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||||
|  |         # IBM's JDK on AIX uses strange locations for the executables | ||||||
|  |         JAVACMD="$JAVA_HOME/jre/sh/java" | ||||||
|  |     else | ||||||
|  |         JAVACMD="$JAVA_HOME/bin/java" | ||||||
|  |     fi | ||||||
|  |     if [ ! -x "$JAVACMD" ] ; then | ||||||
|  |         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||||
|  |  | ||||||
|  | Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | location of your Java installation." | ||||||
|  |     fi | ||||||
|  | else | ||||||
|  |     JAVACMD="java" | ||||||
|  |     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||||
|  |  | ||||||
|  | Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | location of your Java installation." | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Increase the maximum file descriptors if we can. | ||||||
|  | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | ||||||
|  |     MAX_FD_LIMIT=`ulimit -H -n` | ||||||
|  |     if [ $? -eq 0 ] ; then | ||||||
|  |         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||||||
|  |             MAX_FD="$MAX_FD_LIMIT" | ||||||
|  |         fi | ||||||
|  |         ulimit -n $MAX_FD | ||||||
|  |         if [ $? -ne 0 ] ; then | ||||||
|  |             warn "Could not set maximum file descriptor limit: $MAX_FD" | ||||||
|  |         fi | ||||||
|  |     else | ||||||
|  |         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # For Darwin, add options to specify how the application appears in the dock | ||||||
|  | if $darwin; then | ||||||
|  |     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # For Cygwin, switch paths to Windows format before running java | ||||||
|  | if $cygwin ; then | ||||||
|  |     APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||||||
|  |     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||||||
|  |     JAVACMD=`cygpath --unix "$JAVACMD"` | ||||||
|  |  | ||||||
|  |     # We build the pattern for arguments to be converted via cygpath | ||||||
|  |     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||||||
|  |     SEP="" | ||||||
|  |     for dir in $ROOTDIRSRAW ; do | ||||||
|  |         ROOTDIRS="$ROOTDIRS$SEP$dir" | ||||||
|  |         SEP="|" | ||||||
|  |     done | ||||||
|  |     OURCYGPATTERN="(^($ROOTDIRS))" | ||||||
|  |     # Add a user-defined pattern to the cygpath arguments | ||||||
|  |     if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||||||
|  |         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||||||
|  |     fi | ||||||
|  |     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||||
|  |     i=0 | ||||||
|  |     for arg in "$@" ; do | ||||||
|  |         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||||||
|  |         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option | ||||||
|  |  | ||||||
|  |         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition | ||||||
|  |             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||||||
|  |         else | ||||||
|  |             eval `echo args$i`="\"$arg\"" | ||||||
|  |         fi | ||||||
|  |         i=$((i+1)) | ||||||
|  |     done | ||||||
|  |     case $i in | ||||||
|  |         (0) set -- ;; | ||||||
|  |         (1) set -- "$args0" ;; | ||||||
|  |         (2) set -- "$args0" "$args1" ;; | ||||||
|  |         (3) set -- "$args0" "$args1" "$args2" ;; | ||||||
|  |         (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||||||
|  |         (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||||||
|  |         (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||||||
|  |         (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||||||
|  |         (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||||||
|  |         (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||||||
|  |     esac | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Escape application args | ||||||
|  | save () { | ||||||
|  |     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | ||||||
|  |     echo " " | ||||||
|  | } | ||||||
|  | APP_ARGS=$(save "$@") | ||||||
|  |  | ||||||
|  | # Collect all arguments for the java command, following the shell quoting and substitution rules | ||||||
|  | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | ||||||
|  |  | ||||||
|  | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong | ||||||
|  | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then | ||||||
|  |   cd "$(dirname "$0")" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | exec "$JAVACMD" "$@" | ||||||
							
								
								
									
										74
									
								
								gradlew.bat → Forge/gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								gradlew.bat → Forge/gradlew.bat
									
									
									
									
										vendored
									
									
								
							| @@ -1,21 +1,3 @@ | |||||||
| @rem |  | ||||||
| @rem Copyright 2015 the original author or authors. |  | ||||||
| @rem |  | ||||||
| @rem Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| @rem you may not use this file except in compliance with the License. |  | ||||||
| @rem You may obtain a copy of the License at |  | ||||||
| @rem |  | ||||||
| @rem      https://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| @rem |  | ||||||
| @rem Unless required by applicable law or agreed to in writing, software |  | ||||||
| @rem distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| @rem See the License for the specific language governing permissions and |  | ||||||
| @rem limitations under the License. |  | ||||||
| @rem |  | ||||||
| @rem SPDX-License-Identifier: Apache-2.0 |  | ||||||
| @rem |  | ||||||
| 
 |  | ||||||
| @if "%DEBUG%" == "" @echo off | @if "%DEBUG%" == "" @echo off | ||||||
| @rem ########################################################################## | @rem ########################################################################## | ||||||
| @rem | @rem | ||||||
| @@ -28,28 +10,24 @@ if "%OS%"=="Windows_NT" setlocal | |||||||
| 
 | 
 | ||||||
| set DIRNAME=%~dp0 | set DIRNAME=%~dp0 | ||||||
| if "%DIRNAME%" == "" set DIRNAME=. | if "%DIRNAME%" == "" set DIRNAME=. | ||||||
| @rem This is normally unused |  | ||||||
| set APP_BASE_NAME=%~n0 | set APP_BASE_NAME=%~n0 | ||||||
| set APP_HOME=%DIRNAME% | set APP_HOME=%DIRNAME% | ||||||
| 
 | 
 | ||||||
| @rem Resolve any "." and ".." in APP_HOME to make it shorter. |  | ||||||
| for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi |  | ||||||
| 
 |  | ||||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
| set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | set DEFAULT_JVM_OPTS= | ||||||
| 
 | 
 | ||||||
| @rem Find java.exe | @rem Find java.exe | ||||||
| if defined JAVA_HOME goto findJavaFromJavaHome | if defined JAVA_HOME goto findJavaFromJavaHome | ||||||
| 
 | 
 | ||||||
| set JAVA_EXE=java.exe | set JAVA_EXE=java.exe | ||||||
| %JAVA_EXE% -version >NUL 2>&1 | %JAVA_EXE% -version >NUL 2>&1 | ||||||
| if %ERRORLEVEL% equ 0 goto execute | if "%ERRORLEVEL%" == "0" goto init | ||||||
| 
 | 
 | ||||||
| echo. 1>&2 | echo. | ||||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||||
| echo. 1>&2 | echo. | ||||||
| echo Please set the JAVA_HOME variable in your environment to match the 1>&2 | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
| echo location of your Java installation. 1>&2 | echo location of your Java installation. | ||||||
| 
 | 
 | ||||||
| goto fail | goto fail | ||||||
| 
 | 
 | ||||||
| @@ -57,36 +35,48 @@ goto fail | |||||||
| set JAVA_HOME=%JAVA_HOME:"=% | set JAVA_HOME=%JAVA_HOME:"=% | ||||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||||
| 
 | 
 | ||||||
| if exist "%JAVA_EXE%" goto execute | if exist "%JAVA_EXE%" goto init | ||||||
| 
 | 
 | ||||||
| echo. 1>&2 | echo. | ||||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||||
| echo. 1>&2 | echo. | ||||||
| echo Please set the JAVA_HOME variable in your environment to match the 1>&2 | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
| echo location of your Java installation. 1>&2 | echo location of your Java installation. | ||||||
| 
 | 
 | ||||||
| goto fail | goto fail | ||||||
| 
 | 
 | ||||||
|  | :init | ||||||
|  | @rem Get command-line arguments, handling Windows variants | ||||||
|  | 
 | ||||||
|  | if not "%OS%" == "Windows_NT" goto win9xME_args | ||||||
|  | 
 | ||||||
|  | :win9xME_args | ||||||
|  | @rem Slurp the command line arguments. | ||||||
|  | set CMD_LINE_ARGS= | ||||||
|  | set _SKIP=2 | ||||||
|  | 
 | ||||||
|  | :win9xME_args_slurp | ||||||
|  | if "x%~1" == "x" goto execute | ||||||
|  | 
 | ||||||
|  | set CMD_LINE_ARGS=%* | ||||||
|  | 
 | ||||||
| :execute | :execute | ||||||
| @rem Setup the command line | @rem Setup the command line | ||||||
| 
 | 
 | ||||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @rem Execute Gradle | @rem Execute Gradle | ||||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||||||
| 
 | 
 | ||||||
| :end | :end | ||||||
| @rem End local scope for the variables with windows NT shell | @rem End local scope for the variables with windows NT shell | ||||||
| if %ERRORLEVEL% equ 0 goto mainEnd | if "%ERRORLEVEL%"=="0" goto mainEnd | ||||||
| 
 | 
 | ||||||
| :fail | :fail | ||||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||||
| rem the _cmd.exe /c_ return code! | rem the _cmd.exe /c_ return code! | ||||||
| set EXIT_CODE=%ERRORLEVEL% | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||||
| if %EXIT_CODE% equ 0 set EXIT_CODE=1 | exit /b 1 | ||||||
| if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% |  | ||||||
| exit /b %EXIT_CODE% |  | ||||||
| 
 | 
 | ||||||
| :mainEnd | :mainEnd | ||||||
| if "%OS%"=="Windows_NT" endlocal | if "%OS%"=="Windows_NT" endlocal | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| package chylex.customwindowtitle; | package chylex.customwindowtitle; | ||||||
| 
 |  | ||||||
| import org.apache.commons.lang3.ArrayUtils; | import org.apache.commons.lang3.ArrayUtils; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.apache.logging.log4j.LogManager; | import org.apache.logging.log4j.LogManager; | ||||||
| @@ -7,25 +6,25 @@ import org.apache.logging.log4j.Logger; | |||||||
| import java.util.regex.Matcher; | import java.util.regex.Matcher; | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
| 
 | 
 | ||||||
| final class TitleParser { | public final class TitleParser{ | ||||||
| 	private static final Pattern tokenRegex = Pattern.compile("\\{([a-z]+)(?::([^}]+))?}"); | 	private static final Pattern tokenRegex = Pattern.compile("\\{([a-z]+)(?::([^}]+))?}"); | ||||||
| 	private static final Logger logger = LogManager.getLogger("CustomWindowTitle"); | 	private static final Logger logger = LogManager.getLogger("CustomWindowTitle"); | ||||||
| 	 | 	 | ||||||
| 	public static String parse(final String input) { | 	public static String parse(String input){ | ||||||
| 		final StringBuilder buffer = new StringBuilder(); | 		StringBuffer buffer = new StringBuffer(); | ||||||
| 		final Matcher matcher = tokenRegex.matcher(input); | 		Matcher matcher = tokenRegex.matcher(input); | ||||||
| 		 | 		 | ||||||
| 		while(matcher.find()){ | 		while(matcher.find()){ | ||||||
| 			final String token = matcher.group(1); | 			String token = matcher.group(1); | ||||||
| 			final String[] args = StringUtils.split(matcher.group(2), ','); | 			String[] args = StringUtils.split(matcher.group(2), ','); | ||||||
| 			 | 			 | ||||||
| 			String result = null; | 			String result = null; | ||||||
| 			 | 			 | ||||||
| 			try{ | 			try{ | ||||||
| 				result = TitleTokens.getTokenFunction(token).apply(args == null ? ArrayUtils.EMPTY_STRING_ARRAY : args); | 				result = TitleTokens.getTokenFunction(token).apply(args == null ? ArrayUtils.EMPTY_STRING_ARRAY : args); | ||||||
| 			} catch (final TokenException e) { | 			}catch(TokenException e){ | ||||||
| 				logger.warn("Error processing token '" + token + "': " + e.getMessage()); | 				logger.warn("Error processing token '" + token + "': " + e.getMessage()); | ||||||
| 			} catch (final Throwable t) { | 			}catch(Throwable t){ | ||||||
| 				logger.warn("Error processing token '" + token + "': " + t.getMessage(), t); | 				logger.warn("Error processing token '" + token + "': " + t.getMessage(), t); | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| package chylex.customwindowtitle; | package chylex.customwindowtitle; | ||||||
| 
 |  | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.function.Function; | import java.util.function.Function; | ||||||
| @@ -12,29 +11,29 @@ public final class TitleTokens { | |||||||
| 	 | 	 | ||||||
| 	private static final Map<String, Function<String[], String>> tokenMap = new HashMap<>(); | 	private static final Map<String, Function<String[], String>> tokenMap = new HashMap<>(); | ||||||
| 	 | 	 | ||||||
| 	public static void registerToken(final String token, final Function<String[], String> processor) { | 	public static void registerToken(String token, Function<String[], String> processor){ | ||||||
| 		tokenMap.putIfAbsent(token, processor); | 		tokenMap.putIfAbsent(token, processor); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public static Function<String[], String> getTokenFunction(final String token) { | 	public static Function<String[], String> getTokenFunction(String token){ | ||||||
| 		return tokenMap.getOrDefault(token, args -> null); | 		return tokenMap.getOrDefault(token, args -> null); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	// Arguments | 	// Arguments | ||||||
| 	 | 	 | ||||||
| 	public static Function<String[], String> noArgs(final Supplier<String> func) { | 	public static Function<String[], String> noArgs(Supplier<String> func){ | ||||||
| 		return args -> args.length > 0 ? fail("expected no arguments, got " + args.length) : func.get(); | 		return args -> args.length > 0 ? fail("expected no arguments, got " + args.length) : func.get(); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public static Function<String[], String> oneArg(final UnaryOperator<String> func) { | 	public static Function<String[], String> oneArg(UnaryOperator<String> func){ | ||||||
| 		return args -> args.length != 1 ? fail("expected 1 argument, got " + args.length) : func.apply(args[0]); | 		return args -> args.length != 1 ? fail("expected 1 argument, got " + args.length) : func.apply(args[0]); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public static Function<String[], String> rangeArgs(final int min, final int max, final Function<String[], String> func) { | 	public static Function<String[], String> rangeArgs(int min, int max, Function<String[], String> func){ | ||||||
| 		return args -> args.length < min || args.length > max ? fail("expected between " + min + " and " + max + " arguments, got " + args.length) : func.apply(args); | 		return args -> args.length < min || args.length > max ? fail("expected between " + min + " and " + max + " arguments, got " + args.length) : func.apply(args); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	private static String fail(final String message) { | 	private static String fail(String message){ | ||||||
| 		throw new TokenException(message); | 		throw new TokenException(message); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | package chylex.customwindowtitle; | ||||||
|  |  | ||||||
|  | public class TokenException extends RuntimeException{ | ||||||
|  | 	public TokenException(String message){ | ||||||
|  | 		super(message); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,51 @@ | |||||||
|  | package chylex.customwindowtitle.forge; | ||||||
|  | import chylex.customwindowtitle.TitleParser; | ||||||
|  | import net.minecraftforge.fml.common.Mod; | ||||||
|  | import net.minecraftforge.fml.common.Mod.EventHandler; | ||||||
|  | import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.lwjgl.opengl.Display; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.Path; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | import java.util.Collections; | ||||||
|  |  | ||||||
|  | @Mod(modid = "customwindowtitle", useMetadata = true, clientSideOnly = true, acceptedMinecraftVersions = "*", acceptableRemoteVersions = "*") | ||||||
|  | public class CustomWindowTitle{ | ||||||
|  | 	private static final String defaultTitle = "Minecraft {mcversion}"; | ||||||
|  | 	private String configTitle; | ||||||
|  | 	 | ||||||
|  | 	@EventHandler | ||||||
|  | 	public void onPreInit(FMLPreInitializationEvent e){ | ||||||
|  | 		Path configFile = Paths.get(e.getModConfigurationDirectory().getAbsolutePath(), "customwindowtitle-client.toml"); | ||||||
|  | 		 | ||||||
|  | 		try{ | ||||||
|  | 			String prefix = "title = "; | ||||||
|  | 			 | ||||||
|  | 			if (!Files.exists(configFile)){ | ||||||
|  | 				Files.write(configFile, Collections.singletonList(prefix + '"' + defaultTitle + '"'), StandardCharsets.UTF_8); | ||||||
|  | 				configTitle = defaultTitle; | ||||||
|  | 			} | ||||||
|  | 			else{ | ||||||
|  | 				configTitle = Files | ||||||
|  | 					.readAllLines(configFile, StandardCharsets.UTF_8) | ||||||
|  | 					.stream() | ||||||
|  | 					.filter(line -> line.startsWith(prefix)) | ||||||
|  | 					.map(line -> StringUtils.strip(StringUtils.removeStart(line, prefix).trim(), "\"")) | ||||||
|  | 					.findFirst() | ||||||
|  | 					.orElse(defaultTitle); | ||||||
|  | 			} | ||||||
|  | 		}catch(IOException ex){ | ||||||
|  | 			throw new RuntimeException("CustomWindowTitle configuration error", ex); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		TokenData.register(); | ||||||
|  | 		updateTitle(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private void updateTitle(){ | ||||||
|  | 		Display.setTitle(TitleParser.parse(configTitle)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package chylex.customwindowtitle.forge; | ||||||
|  | import chylex.customwindowtitle.TokenException; | ||||||
|  | import net.minecraft.realms.RealmsSharedConstants; | ||||||
|  | import net.minecraftforge.fml.common.Loader; | ||||||
|  | import net.minecraftforge.fml.common.ModContainer; | ||||||
|  | import static chylex.customwindowtitle.TitleTokens.noArgs; | ||||||
|  | import static chylex.customwindowtitle.TitleTokens.oneArg; | ||||||
|  | import static chylex.customwindowtitle.TitleTokens.registerToken; | ||||||
|  |  | ||||||
|  | final class TokenData{ | ||||||
|  | 	static void register(){ | ||||||
|  | 		registerToken("mcversion", noArgs(TokenData::getMinecraftVersion)); | ||||||
|  | 		registerToken("modversion", oneArg(TokenData::getModVersion)); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	static String getMinecraftVersion(){ | ||||||
|  | 		return RealmsSharedConstants.VERSION_STRING; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	static String getModVersion(String modId){ | ||||||
|  | 		ModContainer mod = Loader.instance().getIndexedModList().get(modId); | ||||||
|  | 		 | ||||||
|  | 		if (mod == null){ | ||||||
|  | 			throw new TokenException("mod info for '" + modId + "' not found"); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return mod.getMetadata().version; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								Forge/src/main/resources/mcmod.info
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Forge/src/main/resources/mcmod.info
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | [ | ||||||
|  | { | ||||||
|  |   "modid": "customwindowtitle", | ||||||
|  |   "name": "Custom Window Title", | ||||||
|  |   "description": "", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "url": "https://github.com/chylex/Minecraft-Window-Title", | ||||||
|  |   "authorList": ["chylex"] | ||||||
|  | } | ||||||
|  | ] | ||||||
							
								
								
									
										7
									
								
								Forge/src/main/resources/pack.mcmeta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Forge/src/main/resources/pack.mcmeta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |     "pack": { | ||||||
|  |         "description": "Custom Window Title", | ||||||
|  |         "pack_format": 3, | ||||||
|  |         "_comment": "" | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| import net.neoforged.moddevgradle.dsl.RunModel |  | ||||||
|  |  | ||||||
| val modId: String by project |  | ||||||
| val modSides: String by project |  | ||||||
| val neoForgeVersion: String by project |  | ||||||
|  |  | ||||||
| plugins { |  | ||||||
| 	id("net.neoforged.moddev") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| neoForge { |  | ||||||
| 	version = neoForgeVersion |  | ||||||
| 	 |  | ||||||
| 	mods { |  | ||||||
| 		register(modId) { |  | ||||||
| 			sourceSet(sourceSets.main.get()) |  | ||||||
| 			sourceSet(rootProject.sourceSets.main.get()) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	runs { |  | ||||||
| 		val runJvmArgs: Set<String> by project |  | ||||||
| 		 |  | ||||||
| 		configureEach { |  | ||||||
| 			gameDirectory = file("../run") |  | ||||||
| 			jvmArguments.addAll(runJvmArgs) |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		fun side(name: String, configure: RunModel.() -> Unit) { |  | ||||||
| 			if (modSides == "both" || modSides == name) { |  | ||||||
| 				register(name, configure) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		side("client") { |  | ||||||
| 			ideName.set("NeoForge Client") |  | ||||||
| 			client() |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		side("server") { |  | ||||||
| 			ideName.set("NeoForge Server") |  | ||||||
| 			server() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| tasks.processResources { |  | ||||||
| 	filesMatching("META-INF/neoforge.mods.toml") { |  | ||||||
| 		expand(inputs.properties) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| package chylex.customwindowtitle.neoforge; |  | ||||||
|  |  | ||||||
| import chylex.customwindowtitle.TitleChanger; |  | ||||||
| import chylex.customwindowtitle.TitleConfig; |  | ||||||
| import chylex.customwindowtitle.data.CommonTokenData; |  | ||||||
| import net.neoforged.bus.api.IEventBus; |  | ||||||
| import net.neoforged.bus.api.SubscribeEvent; |  | ||||||
| import net.neoforged.fml.common.Mod; |  | ||||||
| import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; |  | ||||||
| import net.neoforged.fml.loading.FMLPaths; |  | ||||||
|  |  | ||||||
| @Mod("customwindowtitle") |  | ||||||
| public class CustomWindowTitle { |  | ||||||
| 	 |  | ||||||
| 	private final TitleConfig config; |  | ||||||
| 	 |  | ||||||
| 	public CustomWindowTitle(IEventBus eventBus) { |  | ||||||
| 		config = TitleConfig.load(FMLPaths.CONFIGDIR.get().toString()); |  | ||||||
| 		eventBus.addListener(this::onClientSetup); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	@SubscribeEvent |  | ||||||
| 	public void onClientSetup(final FMLClientSetupEvent e) { |  | ||||||
| 		CommonTokenData.register(new TokenProvider()); |  | ||||||
| 		e.enqueueWork(() -> TitleChanger.setTitle(config)); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| package chylex.customwindowtitle.neoforge; |  | ||||||
|  |  | ||||||
| import chylex.customwindowtitle.TokenException; |  | ||||||
| import chylex.customwindowtitle.data.CommonTokenProvider; |  | ||||||
| import net.neoforged.fml.ModList; |  | ||||||
| import net.neoforged.neoforgespi.language.IModFileInfo; |  | ||||||
| import net.neoforged.neoforgespi.language.IModInfo; |  | ||||||
|  |  | ||||||
| final class TokenProvider implements CommonTokenProvider { |  | ||||||
| 	@Override |  | ||||||
| 	public String getModVersion(final String modId) { |  | ||||||
| 		final IModFileInfo file = ModList.get().getModFileById(modId); |  | ||||||
| 		 |  | ||||||
| 		if (file == null) { |  | ||||||
| 			throw new TokenException("mod file for '" + modId + "' not found"); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		for (final IModInfo info : file.getMods()) { |  | ||||||
| 			if (info.getModId().equals(modId)) { |  | ||||||
| 				return info.getVersion().toString(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		throw new TokenException("mod info for '" + modId + "' not found"); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,30 +0,0 @@ | |||||||
| modLoader = "javafml" |  | ||||||
| loaderVersion = "[0,)" |  | ||||||
|  |  | ||||||
| license = "${license}" |  | ||||||
| issueTrackerURL = "${issuesURL}" |  | ||||||
|  |  | ||||||
| [[mods]] |  | ||||||
| modId = "${id}" |  | ||||||
| displayName = "${name}" |  | ||||||
| displayURL = "${sourcesURL}" |  | ||||||
| description = "${description}" |  | ||||||
| authors = "${author}" |  | ||||||
| version = "${version}" |  | ||||||
|  |  | ||||||
| [[mixins]] |  | ||||||
| config = "${id}.mixins.json" |  | ||||||
|  |  | ||||||
| [[dependencies.${id}]] |  | ||||||
| modId = "minecraft" |  | ||||||
| type = "required" |  | ||||||
| versionRange = "[${minimumMinecraftVersion},)" |  | ||||||
| ordering = "NONE" |  | ||||||
| side = "${sidesForNeoForge}" |  | ||||||
|  |  | ||||||
| [[dependencies.${id}]] |  | ||||||
| modId = "neoforge" |  | ||||||
| type = "required" |  | ||||||
| versionRange = "[${minimumNeoForgeVersion},)" |  | ||||||
| ordering = "NONE" |  | ||||||
| side = "${sidesForNeoForge}" |  | ||||||
							
								
								
									
										57
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,59 +2,27 @@ | |||||||
|  |  | ||||||
| ## Installation | ## Installation | ||||||
|  |  | ||||||
| The mod supports [NeoForge](https://neoforged.net/) and [Fabric](https://fabricmc.net/) (*) mod loaders. Follow either mod loader's installation guide, then download the mod file for your Minecraft version from [CurseForge](https://www.curseforge.com/minecraft/mc-mods/custom-window-title/files) or [Modrinth](https://modrinth.com/mod/custom-window-title/versions), and install it into the `.minecraft/mods` folder. | The mod supports [Forge](https://files.minecraftforge.net/) and [Fabric](https://fabricmc.net/) (*) mod loaders, **the same mod file will work in both**. Follow either mod loader's installation guide, then [download the mod file](https://www.curseforge.com/minecraft/mc-mods/custom-window-title/files) for your Minecraft version, and install it into the **.minecraft/mods** folder. | ||||||
|  |  | ||||||
| (*) Fabric API is **not** required. | (*) Fabric API is not required. | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
|  |  | ||||||
| Run the game once to create the configuration file. By default, the window title will be set to **Minecraft _<version>_**. Unlike in vanilla 1.15.2 onwards, the title will not change when you enter a world/server. | Run the game once to create the configuration file. By default, the window title will be set to **Minecraft _<version>_**. Unlike in vanilla 1.15.2 onwards, the title will not change when you enter a world/server. | ||||||
|  |  | ||||||
| To change the title or icon, navigate to the `.minecraft/config` folder, and open `customwindowtitle-client.toml` in a text editor. You will see the following entries: | To change the title, navigate to the **.minecraft/config** folder, and open **customwindowtitle-client.toml** in a text editor. You will see the following line: | ||||||
|  |  | ||||||
| ```toml | ```toml | ||||||
| title = 'Minecraft {mcversion}'   | title = "Minecraft {mcversion}" | ||||||
| icon = ''   |  | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Only edit text inside quotes or apostrophes. | Change only text inside the quotes. You can use the following special tokens: | ||||||
|  |  | ||||||
| ### Changing the Title | * **{mcversion}** - current Minecraft version | ||||||
|  | * **{modversion:<span style="text-decoration: underline;">modid</span>}** - version of installed mod with the identifier _modid_ | ||||||
| You can use the following special tokens in the _title_ configuration entry: |  | ||||||
|  |  | ||||||
| * `{mcversion}` - current Minecraft version |  | ||||||
| * `{modversion:<mod_id>}` - version of installed mod with the identifier `<mod_id>` |  | ||||||
| * `{username}` - current username |  | ||||||
|  |  | ||||||
| If any of the tokens aren't working, search the game log for **CustomWindowTitle** and you should see the reason, otherwise please file an issue on the [issue tracker](https://github.com/chylex/Minecraft-Window-Title/issues) with as many details as possible. | If any of the tokens aren't working, search the game log for **CustomWindowTitle** and you should see the reason, otherwise please file an issue on the [issue tracker](https://github.com/chylex/Minecraft-Window-Title/issues) with as many details as possible. | ||||||
|  |  | ||||||
| ### Changing the Icon |  | ||||||
|  |  | ||||||
| #### Minecraft 1.21+ |  | ||||||
|  |  | ||||||
| **This feature is only available in Custom Window Title 1.4.0 and newer.** |  | ||||||
|  |  | ||||||
| Create a square PNG image whose dimensions are a power of two, such as 32x32 or 48x48. Put the PNG file into the `.minecraft/config` folder, either directly or into a subfolder. |  | ||||||
|  |  | ||||||
| The icon **must be saved with transparency** even if it doesn't use it, otherwise the icon may be corrupted or not appear at all. In Krita, for example, you must check _Store alpha channel (transparency)_ when saving. |  | ||||||
|  |  | ||||||
| The _icon_ configuration entry points to the PNG file relative to `.minecraft/config`. |  | ||||||
|  |  | ||||||
| For example, if you placed the icon into `.minecraft/config/customwindowtitle/icon.png`, then the configuration entry should look like this: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| icon = 'customwindowtitle/icon.png' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| #### Minecraft 1.20 |  | ||||||
|  |  | ||||||
| This feature is not available in Minecraft 1.20. |  | ||||||
|  |  | ||||||
| #### Minecraft 1.19 and older |  | ||||||
|  |  | ||||||
| Instead of one `icon` configuration entry, there are two configuration entries `icon16` and `icon32` for icons with dimensions 16x16 and 32x32. |  | ||||||
|  |  | ||||||
| ## Screenshots | ## Screenshots | ||||||
|  |  | ||||||
| These screenshots were taken using the following example configuration: | These screenshots were taken using the following example configuration: | ||||||
| @@ -63,15 +31,10 @@ These screenshots were taken using the following example configuration: | |||||||
| title = "Minecraft {mcversion} - Custom Window Title {modversion:customwindowtitle}" | title = "Minecraft {mcversion} - Custom Window Title {modversion:customwindowtitle}" | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # For Developers | # For Developers | ||||||
|  |  | ||||||
| The mod sources are organized into 3 projects: | Currently the common source files (package `chylex.customwindowtitle`) are just duplicated in the Forge and Fabric folders, and the jar files are combined with a horrible python script. If anyone has the time and patience to clean it up, I'd appreciate a Pull Request :P | ||||||
| - `src/` contains common source files and mixins |  | ||||||
| - `Fabric/src/` contains source files specific for Fabric |  | ||||||
| - `NeoForge/src/` contains source files specific for NeoForge |  | ||||||
|  |  | ||||||
| The `assemble` Gradle task creates a single `.jar` file for both mod loaders in the `build/dist` folder. | For now, you can build either separate Forge and Fabric projects using `gradlew build` in either folder, or run `python BuildMerge.py` to automatically build both and combine them into a single `.jar` file. | ||||||
|  |  | ||||||
| When building against a Minecraft version that is only supported by one mod loader, open `gradle.properties` and comment or remove either `neoForgeVersion` or `fabricVersion` to disable them. |  | ||||||
|   | |||||||
							
								
								
									
										214
									
								
								build.gradle.kts
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								build.gradle.kts
									
									
									
									
									
								
							| @@ -1,214 +0,0 @@ | |||||||
| @file:Suppress("ConvertLambdaToReference") |  | ||||||
|  |  | ||||||
| import org.gradle.jvm.tasks.Jar |  | ||||||
|  |  | ||||||
| val modId: String by project |  | ||||||
| val modName: String by project |  | ||||||
| val modDescription: String by project |  | ||||||
| val modAuthor: String by project |  | ||||||
| val modVersion: String by project |  | ||||||
| val modLicense: String by project |  | ||||||
| val modSourcesURL: String by project |  | ||||||
| val modIssuesURL: String by project |  | ||||||
| val modSides: String by project |  | ||||||
|  |  | ||||||
| val minecraftVersion: String by project |  | ||||||
| val mixinVersion: String by project |  | ||||||
|  |  | ||||||
| val minimumMinecraftVersion: String by project |  | ||||||
| val minimumNeoForgeVersion: String by project |  | ||||||
| val minimumFabricVersion: String by project |  | ||||||
|  |  | ||||||
| val modNameStripped = modName.replace(" ", "") |  | ||||||
|  |  | ||||||
| plugins { |  | ||||||
| 	idea |  | ||||||
| 	`java-library` |  | ||||||
| 	id("fabric-loom") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| idea { |  | ||||||
| 	module { |  | ||||||
| 		excludeDirs.add(file("gradle")) |  | ||||||
| 		excludeDirs.add(file("run")) |  | ||||||
| 		 |  | ||||||
| 		if (findProject(":NeoForge") == null) { |  | ||||||
| 			excludeDirs.add(file("NeoForge")) |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		if (findProject(":Fabric") == null) { |  | ||||||
| 			excludeDirs.add(file("Fabric")) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| repositories { |  | ||||||
| 	mavenCentral() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| base { |  | ||||||
| 	archivesName.set("$modNameStripped-Common") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| loom { |  | ||||||
| 	runs { |  | ||||||
| 		named("client") { |  | ||||||
| 			ideConfigGenerated(false) |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		findByName("server")?.let(::remove) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| dependencies { |  | ||||||
| 	minecraft("com.mojang:minecraft:$minecraftVersion") |  | ||||||
| 	mappings(loom.officialMojangMappings()) |  | ||||||
| 	 |  | ||||||
| 	compileOnly("net.fabricmc:sponge-mixin:$mixinVersion") |  | ||||||
| 	api("com.google.code.findbugs:jsr305:3.0.2") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| allprojects { |  | ||||||
| 	group = "com.$modAuthor.$modId" |  | ||||||
| 	version = modVersion |  | ||||||
| 	 |  | ||||||
| 	apply(plugin = "java-library") |  | ||||||
| 	 |  | ||||||
| 	extensions.getByType<JavaPluginExtension>().apply { |  | ||||||
| 		toolchain.languageVersion.set(JavaLanguageVersion.of(21)) |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.withType<JavaCompile> { |  | ||||||
| 		options.encoding = "UTF-8" |  | ||||||
| 		options.release.set(21) |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	val runJvmArgs = mutableSetOf<String>().also { |  | ||||||
| 		extra["runJvmArgs"] = it |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	if (project.javaToolchains.launcherFor(java.toolchain).map { it.metadata.vendor }.orNull == "JetBrains") { |  | ||||||
| 		runJvmArgs.add("-XX:+AllowEnhancedClassRedefinition") |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	dependencies { |  | ||||||
| 		implementation("org.jetbrains:annotations:24.1.0") |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.withType<ProcessResources> { |  | ||||||
| 		val (sidesForNeoForge, sidesForFabric) = when (modSides) { |  | ||||||
| 			"both"   -> Pair("BOTH", "*") |  | ||||||
| 			"client" -> Pair("CLIENT", "client") |  | ||||||
| 			"server" -> Pair("SERVER", "server") |  | ||||||
| 			else     -> error("Invalid modSides value: $modSides") |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		inputs.property("id", modId) |  | ||||||
| 		inputs.property("name", modName) |  | ||||||
| 		inputs.property("description", modDescription) |  | ||||||
| 		inputs.property("version", modVersion) |  | ||||||
| 		inputs.property("author", modAuthor) |  | ||||||
| 		inputs.property("license", modLicense) |  | ||||||
| 		inputs.property("sourcesURL", modSourcesURL) |  | ||||||
| 		inputs.property("issuesURL", modIssuesURL) |  | ||||||
| 		inputs.property("sidesForNeoForge", sidesForNeoForge) |  | ||||||
| 		inputs.property("sidesForFabric", sidesForFabric) |  | ||||||
| 		inputs.property("minimumMinecraftVersion", minimumMinecraftVersion) |  | ||||||
| 		inputs.property("minimumNeoForgeVersion", minimumNeoForgeVersion) |  | ||||||
| 		inputs.property("minimumFabricVersion", minimumFabricVersion) |  | ||||||
| 		 |  | ||||||
| 		from(rootProject.file("logo.png")) { |  | ||||||
| 			into("assets/$modId") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.withType<AbstractArchiveTask>().configureEach { |  | ||||||
| 		isPreserveFileTimestamps = false |  | ||||||
| 		isReproducibleFileOrder = true |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| subprojects { |  | ||||||
| 	dependencies { |  | ||||||
| 		implementation(project(rootProject.path, configuration = "namedElements")) |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	base { |  | ||||||
| 		archivesName.set("$modNameStripped-${project.name}") |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.compileJava { |  | ||||||
| 		source({ rootProject.sourceSets.main.get().allSource }) |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.processResources { |  | ||||||
| 		from(rootProject.sourceSets.main.get().resources) { |  | ||||||
| 			expand(inputs.properties) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.jar { |  | ||||||
| 		entryCompression = ZipEntryCompression.STORED // Reduces size of multiloader jar. |  | ||||||
| 		 |  | ||||||
| 		manifest { |  | ||||||
| 			packageInformation(modId, "$modNameStripped-${project.name}") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	tasks.test { |  | ||||||
| 		onlyIf { false } |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fun Manifest.packageInformation(specificationTitle: String, implementationTitle: String) { |  | ||||||
| 	attributes( |  | ||||||
| 		"Specification-Title" to specificationTitle, |  | ||||||
| 		"Specification-Vendor" to modAuthor, |  | ||||||
| 		"Specification-Version" to "1", |  | ||||||
| 		"Implementation-Title" to implementationTitle, |  | ||||||
| 		"Implementation-Vendor" to modAuthor, |  | ||||||
| 		"Implementation-Version" to modVersion, |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| val multiloaderSources = sourceSets.register("multiloader") |  | ||||||
|  |  | ||||||
| val multiloaderJar = tasks.register<Jar>("multiloaderJar") { |  | ||||||
| 	group = "build" |  | ||||||
| 	 |  | ||||||
| 	archiveBaseName.set(modNameStripped) |  | ||||||
| 	archiveVersion.set("$minecraftVersion+v$modVersion") |  | ||||||
| 	 |  | ||||||
| 	destinationDirectory = layout.buildDirectory.dir("dist") |  | ||||||
| 	 |  | ||||||
| 	fun includeJar(project: Project, jarTaskName: String) { |  | ||||||
| 		from(project.tasks.named(jarTaskName).map { it.outputs }) { |  | ||||||
| 			into("jars") |  | ||||||
| 			rename { "$modNameStripped-${project.name}.jar" } |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	findProject(":NeoForge")?.let { includeJar(it, "jar") } |  | ||||||
| 	findProject(":Fabric")?.let { includeJar(it, "uncompressedRemapJar") } |  | ||||||
| 	 |  | ||||||
| 	from(rootProject.file("LICENSE")) |  | ||||||
| 	from(multiloaderSources.map { it.output }) |  | ||||||
| 	 |  | ||||||
| 	manifest { |  | ||||||
| 		packageInformation("$modId-multiloader", modNameStripped) |  | ||||||
| 		attributes("FMLModType" to "GAMELIBRARY") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| tasks.named<ProcessResources>("processMultiloaderResources").configure { |  | ||||||
| 	inputs.property("group", project.group) |  | ||||||
| 	inputs.property("jarPrefix", modNameStripped) |  | ||||||
| 	 |  | ||||||
| 	filesMatching(listOf("fabric.mod.json", "META-INF/jarjar/metadata.json")) { |  | ||||||
| 		expand(inputs.properties) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| tasks.assemble { |  | ||||||
| 	finalizedBy(multiloaderJar) |  | ||||||
| } |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| ## Installation |  | ||||||
|  |  | ||||||
| The mod supports [NeoForge](https://neoforged.net/) and [Fabric](https://fabricmc.net/) (*) mod loaders. Follow either mod loader's installation guide, then [download the mod file](https://www.curseforge.com/minecraft/mc-mods/custom-window-title/files) for your Minecraft version, and install it into the `.minecraft/mods` folder. |  | ||||||
|  |  | ||||||
| (*) Fabric API is **not** required. |  | ||||||
|  |  | ||||||
| ## Configuration |  | ||||||
|  |  | ||||||
| Run the game once to create the configuration file. By default, the window title will be set to **Minecraft _<version>_**. Unlike in vanilla 1.15.2 onwards, the title will not change when you enter a world/server. |  | ||||||
|  |  | ||||||
| To change the title or icon, navigate to the `.minecraft/config` folder, and open `customwindowtitle-client.toml` in a text editor. You will see the following entries: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| title = 'Minecraft {mcversion}'   |  | ||||||
| icon16 = ''   |  | ||||||
| icon32 = '' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Only edit text inside quotes or apostrophes. |  | ||||||
|  |  | ||||||
| ### Changing the Title |  | ||||||
|  |  | ||||||
| You can use the following special tokens in the _title_ configuration entry: |  | ||||||
|  |  | ||||||
| * `{mcversion}` - current Minecraft version |  | ||||||
| * `{modversion:mod_id}` - version of installed mod with the identifier `mod_id` |  | ||||||
| * `{username}` - current username |  | ||||||
|  |  | ||||||
| If any of the tokens aren't working, search the game log for **CustomWindowTitle** and you should see the reason, otherwise please file an issue on the [issue tracker](https://github.com/chylex/Minecraft-Window-Title/issues) with as many details as possible. |  | ||||||
|  |  | ||||||
| ### Changing the Icon |  | ||||||
|  |  | ||||||
| #### Minecraft 1.21+ |  | ||||||
|  |  | ||||||
| **This feature is only available in Custom Window Title 1.4.0 and newer.** |  | ||||||
|  |  | ||||||
| Create a square PNG image whose dimensions are a power of two, such as 32x32 or 48x48. Put the PNG file into the `.minecraft/config` folder, either directly or into a subfolder. |  | ||||||
|  |  | ||||||
| The icon **must be saved with transparency** even if it doesn't use it, otherwise the icon may be corrupted or not appear at all. In Krita, for example, you must check _Store alpha channel (transparency)_ when saving. |  | ||||||
|  |  | ||||||
| The _icon_ configuration entry points to the PNG file relative to `.minecraft/config`. |  | ||||||
|  |  | ||||||
| For example, if you placed the icon into `.minecraft/config/customwindowtitle/icon.png`, then the configuration entry should look like this: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| icon = 'customwindowtitle/icon.png' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| #### Minecraft 1.20 |  | ||||||
|  |  | ||||||
| This feature is not available in Minecraft 1.20. |  | ||||||
|  |  | ||||||
| #### Minecraft 1.19 and older |  | ||||||
|  |  | ||||||
| Instead of one `icon` configuration entry, there are two configuration entries `icon16` and `icon32` for icons with dimensions 16x16 and 32x32. |  | ||||||
|  |  | ||||||
| ## Screenshots |  | ||||||
|  |  | ||||||
| These screenshots were taken using the following example configuration: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| title = "Minecraft {mcversion} - Custom Window Title {modversion:customwindowtitle}" |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| <img src="https://media.forgecdn.net/attachments/277/212/customwindowtitlefabric.png" width="417" height="284"><img src="https://media.forgecdn.net/attachments/277/213/customwindowtitleforge.png" alt="" width="417" height="284"> |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
| ## Installation |  | ||||||
|  |  | ||||||
| The mod supports [NeoForge](https://neoforged.net/) and [Fabric](https://fabricmc.net/) (*) mod loaders. Follow either mod loader's installation guide, then [download the mod file](https://modrinth.com/mod/custom-window-title/versions) for your Minecraft version, and install it into the `.minecraft/mods` folder. |  | ||||||
|  |  | ||||||
| (*) Fabric API is **not** required. |  | ||||||
|  |  | ||||||
| ## Configuration |  | ||||||
|  |  | ||||||
| Run the game once to create the configuration file. By default, the window title will be set to **Minecraft _<version>_**. Unlike in vanilla 1.15.2 onwards, the title will not change when you enter a world/server. |  | ||||||
|  |  | ||||||
| To change the title or icon, navigate to the `.minecraft/config` folder, and open `customwindowtitle-client.toml` in a text editor. You will see the following entries: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| title = 'Minecraft {mcversion}'   |  | ||||||
| icon16 = ''   |  | ||||||
| icon32 = '' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Only edit text inside quotes or apostrophes. |  | ||||||
|  |  | ||||||
| ### Changing the Title |  | ||||||
|  |  | ||||||
| You can use the following special tokens in the _title_ configuration entry: |  | ||||||
|  |  | ||||||
| * `{mcversion}` - current Minecraft version |  | ||||||
| * `{modversion:<mod_id>}` - version of installed mod with the identifier `<mod_id>` |  | ||||||
| * `{username}` - current username |  | ||||||
|  |  | ||||||
| If any of the tokens aren't working, search the game log for **CustomWindowTitle** and you should see the reason, otherwise please file an issue on the [issue tracker](https://github.com/chylex/Minecraft-Window-Title/issues) with as many details as possible. |  | ||||||
|  |  | ||||||
| ### Changing the Icon |  | ||||||
|  |  | ||||||
| #### Minecraft 1.21+ |  | ||||||
|  |  | ||||||
| **This feature is only available in Custom Window Title 1.4.0 and newer.** |  | ||||||
|  |  | ||||||
| Create a square PNG image whose dimensions are a power of two, such as 32x32 or 48x48. Put the PNG file into the `.minecraft/config` folder, either directly or into a subfolder. |  | ||||||
|  |  | ||||||
| The icon **must be saved with transparency** even if it doesn't use it, otherwise the icon may be corrupted or not appear at all. In Krita, for example, you must check _Store alpha channel (transparency)_ when saving. |  | ||||||
|  |  | ||||||
| The _icon_ configuration entry points to the PNG file relative to `.minecraft/config`. |  | ||||||
|  |  | ||||||
| For example, if you placed the icon into `.minecraft/config/customwindowtitle/icon.png`, then the configuration entry should look like this: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| icon = 'customwindowtitle/icon.png' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| #### Minecraft 1.20 |  | ||||||
|  |  | ||||||
| This feature is not available in Minecraft 1.20. |  | ||||||
|  |  | ||||||
| #### Minecraft 1.19 and older |  | ||||||
|  |  | ||||||
| Instead of one `icon` configuration entry, there are two configuration entries `icon16` and `icon32` for icons with dimensions 16x16 and 32x32. |  | ||||||
|  |  | ||||||
| ## Screenshots |  | ||||||
|  |  | ||||||
| These screenshots were taken using the following example configuration: |  | ||||||
|  |  | ||||||
| ```toml |  | ||||||
| title = "Minecraft {mcversion} - Custom Window Title {modversion:customwindowtitle}" |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| # Mod |  | ||||||
| modId=customwindowtitle |  | ||||||
| modName=Custom Window Title |  | ||||||
| modDescription=Customize window title and icon. |  | ||||||
| modAuthor=chylex |  | ||||||
| modVersion=1.4.1 |  | ||||||
| modLicense=Unlicense |  | ||||||
| modSourcesURL=https://github.com/chylex/Minecraft-Window-Title |  | ||||||
| modIssuesURL=https://github.com/chylex/Minecraft-Window-Title/issues |  | ||||||
| modSides=client |  | ||||||
|  |  | ||||||
| # Dependencies |  | ||||||
| minecraftVersion=1.21.4 |  | ||||||
| neoForgeVersion=21.4.77-beta |  | ||||||
| neoModDevVersion=2.0.76 |  | ||||||
| fabricVersion=0.16.10 |  | ||||||
| loomVersion=1.9 |  | ||||||
| mixinVersion=0.12.5+mixin.0.8.5 |  | ||||||
|  |  | ||||||
| # https://projects.neoforged.net/neoforged/neoforge |  | ||||||
| # https://projects.neoforged.net/neoforged/moddevgradle |  | ||||||
| # https://fabricmc.net/develop/ |  | ||||||
| # https://github.com/FabricMC/fabric-loom/releases |  | ||||||
|  |  | ||||||
| # Constraints |  | ||||||
| minimumMinecraftVersion=1.21 |  | ||||||
| minimumNeoForgeVersion=21.0.0-beta |  | ||||||
| minimumFabricVersion=0.12.3 |  | ||||||
|  |  | ||||||
| # Gradle |  | ||||||
| org.gradle.jvmargs=-Xmx3G |  | ||||||
| org.gradle.daemon=false |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										251
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										251
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							| @@ -1,251 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
|  |  | ||||||
| # |  | ||||||
| # Copyright © 2015-2021 the original authors. |  | ||||||
| # |  | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
| # you may not use this file except in compliance with the License. |  | ||||||
| # You may obtain a copy of the License at |  | ||||||
| # |  | ||||||
| #      https://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
| # |  | ||||||
| # Unless required by applicable law or agreed to in writing, software |  | ||||||
| # distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
| # See the License for the specific language governing permissions and |  | ||||||
| # limitations under the License. |  | ||||||
| # |  | ||||||
| # SPDX-License-Identifier: Apache-2.0 |  | ||||||
| # |  | ||||||
|  |  | ||||||
| ############################################################################## |  | ||||||
| # |  | ||||||
| #   Gradle start up script for POSIX generated by Gradle. |  | ||||||
| # |  | ||||||
| #   Important for running: |  | ||||||
| # |  | ||||||
| #   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is |  | ||||||
| #       noncompliant, but you have some other compliant shell such as ksh or |  | ||||||
| #       bash, then to run this script, type that shell name before the whole |  | ||||||
| #       command line, like: |  | ||||||
| # |  | ||||||
| #           ksh Gradle |  | ||||||
| # |  | ||||||
| #       Busybox and similar reduced shells will NOT work, because this script |  | ||||||
| #       requires all of these POSIX shell features: |  | ||||||
| #         * functions; |  | ||||||
| #         * expansions «$var», «${var}», «${var:-default}», «${var+SET}», |  | ||||||
| #           «${var#prefix}», «${var%suffix}», and «$( cmd )»; |  | ||||||
| #         * compound commands having a testable exit status, especially «case»; |  | ||||||
| #         * various built-in commands including «command», «set», and «ulimit». |  | ||||||
| # |  | ||||||
| #   Important for patching: |  | ||||||
| # |  | ||||||
| #   (2) This script targets any POSIX shell, so it avoids extensions provided |  | ||||||
| #       by Bash, Ksh, etc; in particular arrays are avoided. |  | ||||||
| # |  | ||||||
| #       The "traditional" practice of packing multiple parameters into a |  | ||||||
| #       space-separated string is a well documented source of bugs and security |  | ||||||
| #       problems, so this is (mostly) avoided, by progressively accumulating |  | ||||||
| #       options in "$@", and eventually passing that to Java. |  | ||||||
| # |  | ||||||
| #       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, |  | ||||||
| #       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; |  | ||||||
| #       see the in-line comments for details. |  | ||||||
| # |  | ||||||
| #       There are tweaks for specific operating systems such as AIX, CygWin, |  | ||||||
| #       Darwin, MinGW, and NonStop. |  | ||||||
| # |  | ||||||
| #   (3) This script is generated from the Groovy template |  | ||||||
| #       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt |  | ||||||
| #       within the Gradle project. |  | ||||||
| # |  | ||||||
| #       You can find Gradle at https://github.com/gradle/gradle/. |  | ||||||
| # |  | ||||||
| ############################################################################## |  | ||||||
|  |  | ||||||
| # Attempt to set APP_HOME |  | ||||||
|  |  | ||||||
| # Resolve links: $0 may be a link |  | ||||||
| app_path=$0 |  | ||||||
|  |  | ||||||
| # Need this for daisy-chained symlinks. |  | ||||||
| while |  | ||||||
|     APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path |  | ||||||
|     [ -h "$app_path" ] |  | ||||||
| do |  | ||||||
|     ls=$( ls -ld "$app_path" ) |  | ||||||
|     link=${ls#*' -> '} |  | ||||||
|     case $link in             #( |  | ||||||
|       /*)   app_path=$link ;; #( |  | ||||||
|       *)    app_path=$APP_HOME$link ;; |  | ||||||
|     esac |  | ||||||
| done |  | ||||||
|  |  | ||||||
| # This is normally unused |  | ||||||
| # shellcheck disable=SC2034 |  | ||||||
| APP_BASE_NAME=${0##*/} |  | ||||||
| # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) |  | ||||||
| APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit |  | ||||||
|  |  | ||||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. |  | ||||||
| MAX_FD=maximum |  | ||||||
|  |  | ||||||
| warn () { |  | ||||||
|     echo "$*" |  | ||||||
| } >&2 |  | ||||||
|  |  | ||||||
| die () { |  | ||||||
|     echo |  | ||||||
|     echo "$*" |  | ||||||
|     echo |  | ||||||
|     exit 1 |  | ||||||
| } >&2 |  | ||||||
|  |  | ||||||
| # OS specific support (must be 'true' or 'false'). |  | ||||||
| cygwin=false |  | ||||||
| msys=false |  | ||||||
| darwin=false |  | ||||||
| nonstop=false |  | ||||||
| case "$( uname )" in                #( |  | ||||||
|   CYGWIN* )         cygwin=true  ;; #( |  | ||||||
|   Darwin* )         darwin=true  ;; #( |  | ||||||
|   MSYS* | MINGW* )  msys=true    ;; #( |  | ||||||
|   NONSTOP* )        nonstop=true ;; |  | ||||||
| esac |  | ||||||
|  |  | ||||||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Determine the Java command to use to start the JVM. |  | ||||||
| if [ -n "$JAVA_HOME" ] ; then |  | ||||||
|     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |  | ||||||
|         # IBM's JDK on AIX uses strange locations for the executables |  | ||||||
|         JAVACMD=$JAVA_HOME/jre/sh/java |  | ||||||
|     else |  | ||||||
|         JAVACMD=$JAVA_HOME/bin/java |  | ||||||
|     fi |  | ||||||
|     if [ ! -x "$JAVACMD" ] ; then |  | ||||||
|         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |  | ||||||
|  |  | ||||||
| Please set the JAVA_HOME variable in your environment to match the |  | ||||||
| location of your Java installation." |  | ||||||
|     fi |  | ||||||
| else |  | ||||||
|     JAVACMD=java |  | ||||||
|     if ! command -v java >/dev/null 2>&1 |  | ||||||
|     then |  | ||||||
|         die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |  | ||||||
|  |  | ||||||
| Please set the JAVA_HOME variable in your environment to match the |  | ||||||
| location of your Java installation." |  | ||||||
|     fi |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # Increase the maximum file descriptors if we can. |  | ||||||
| if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then |  | ||||||
|     case $MAX_FD in #( |  | ||||||
|       max*) |  | ||||||
|         # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. |  | ||||||
|         # shellcheck disable=SC2039,SC3045 |  | ||||||
|         MAX_FD=$( ulimit -H -n ) || |  | ||||||
|             warn "Could not query maximum file descriptor limit" |  | ||||||
|     esac |  | ||||||
|     case $MAX_FD in  #( |  | ||||||
|       '' | soft) :;; #( |  | ||||||
|       *) |  | ||||||
|         # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. |  | ||||||
|         # shellcheck disable=SC2039,SC3045 |  | ||||||
|         ulimit -n "$MAX_FD" || |  | ||||||
|             warn "Could not set maximum file descriptor limit to $MAX_FD" |  | ||||||
|     esac |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # Collect all arguments for the java command, stacking in reverse order: |  | ||||||
| #   * args from the command line |  | ||||||
| #   * the main class name |  | ||||||
| #   * -classpath |  | ||||||
| #   * -D...appname settings |  | ||||||
| #   * --module-path (only if needed) |  | ||||||
| #   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. |  | ||||||
|  |  | ||||||
| # For Cygwin or MSYS, switch paths to Windows format before running java |  | ||||||
| if "$cygwin" || "$msys" ; then |  | ||||||
|     APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) |  | ||||||
|     CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) |  | ||||||
|  |  | ||||||
|     JAVACMD=$( cygpath --unix "$JAVACMD" ) |  | ||||||
|  |  | ||||||
|     # Now convert the arguments - kludge to limit ourselves to /bin/sh |  | ||||||
|     for arg do |  | ||||||
|         if |  | ||||||
|             case $arg in                                #( |  | ||||||
|               -*)   false ;;                            # don't mess with options #( |  | ||||||
|               /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath |  | ||||||
|                     [ -e "$t" ] ;;                      #( |  | ||||||
|               *)    false ;; |  | ||||||
|             esac |  | ||||||
|         then |  | ||||||
|             arg=$( cygpath --path --ignore --mixed "$arg" ) |  | ||||||
|         fi |  | ||||||
|         # Roll the args list around exactly as many times as the number of |  | ||||||
|         # args, so each arg winds up back in the position where it started, but |  | ||||||
|         # possibly modified. |  | ||||||
|         # |  | ||||||
|         # NB: a `for` loop captures its iteration list before it begins, so |  | ||||||
|         # changing the positional parameters here affects neither the number of |  | ||||||
|         # iterations, nor the values presented in `arg`. |  | ||||||
|         shift                   # remove old arg |  | ||||||
|         set -- "$@" "$arg"      # push replacement arg |  | ||||||
|     done |  | ||||||
| fi |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |  | ||||||
| DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' |  | ||||||
|  |  | ||||||
| # Collect all arguments for the java command: |  | ||||||
| #   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, |  | ||||||
| #     and any embedded shellness will be escaped. |  | ||||||
| #   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be |  | ||||||
| #     treated as '${Hostname}' itself on the command line. |  | ||||||
|  |  | ||||||
| set -- \ |  | ||||||
|         "-Dorg.gradle.appname=$APP_BASE_NAME" \ |  | ||||||
|         -classpath "$CLASSPATH" \ |  | ||||||
|         org.gradle.wrapper.GradleWrapperMain \ |  | ||||||
|         "$@" |  | ||||||
|  |  | ||||||
| # Stop when "xargs" is not available. |  | ||||||
| if ! command -v xargs >/dev/null 2>&1 |  | ||||||
| then |  | ||||||
|     die "xargs is not available" |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| # Use "xargs" to parse quoted args. |  | ||||||
| # |  | ||||||
| # With -n1 it outputs one arg per line, with the quotes and backslashes removed. |  | ||||||
| # |  | ||||||
| # In Bash we could simply go: |  | ||||||
| # |  | ||||||
| #   readarray ARGS < <( xargs -n1 <<<"$var" ) && |  | ||||||
| #   set -- "${ARGS[@]}" "$@" |  | ||||||
| # |  | ||||||
| # but POSIX shell has neither arrays nor command substitution, so instead we |  | ||||||
| # post-process each arg (as a line of input to sed) to backslash-escape any |  | ||||||
| # character that might be a shell metacharacter, then use eval to reverse |  | ||||||
| # that process (while maintaining the separation between arguments), and wrap |  | ||||||
| # the whole thing up as a single "set" statement. |  | ||||||
| # |  | ||||||
| # This will of course break if any of these variables contains a newline or |  | ||||||
| # an unmatched quote. |  | ||||||
| # |  | ||||||
|  |  | ||||||
| eval "set -- $( |  | ||||||
|         printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | |  | ||||||
|         xargs -n1 | |  | ||||||
|         sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | |  | ||||||
|         tr '\n' ' ' |  | ||||||
|     )" '"$@"' |  | ||||||
|  |  | ||||||
| exec "$JAVACMD" "$@" |  | ||||||
| @@ -1,29 +0,0 @@ | |||||||
| rootProject.name = "Minecraft-Window-Title" |  | ||||||
|  |  | ||||||
| pluginManagement { |  | ||||||
| 	repositories { |  | ||||||
| 		gradlePluginPortal() |  | ||||||
| 		maven(url = "https://maven.neoforged.net/releases") { name = "NeoForge" } |  | ||||||
| 		maven(url = "https://maven.fabricmc.net/") { name = "Fabric" } |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	plugins { |  | ||||||
| 		val neoModDevVersion = settings.extra.get("neoModDevVersion") as? String |  | ||||||
| 		if (neoModDevVersion != null) { |  | ||||||
| 			id("net.neoforged.moddev") version neoModDevVersion |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		val loomVersion = settings.extra.get("loomVersion") as? String |  | ||||||
| 		if (loomVersion != null) { |  | ||||||
| 			id("fabric-loom") version "$loomVersion-SNAPSHOT" |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (settings.extra.has("neoForgeVersion")) { |  | ||||||
| 	include("NeoForge") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (settings.extra.has("fabricVersion")) { |  | ||||||
| 	include("Fabric") |  | ||||||
| } |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| package chylex.customwindowtitle; |  | ||||||
|  |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
| import org.apache.logging.log4j.LogManager; |  | ||||||
| import org.apache.logging.log4j.Logger; |  | ||||||
| import org.lwjgl.glfw.GLFW; |  | ||||||
| import org.lwjgl.glfw.GLFWImage; |  | ||||||
| import org.lwjgl.stb.STBImage; |  | ||||||
| import org.lwjgl.system.MemoryStack; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.nio.ByteBuffer; |  | ||||||
| import java.nio.IntBuffer; |  | ||||||
| import java.nio.file.Files; |  | ||||||
| import java.nio.file.Path; |  | ||||||
|  |  | ||||||
| public final class IconChanger { |  | ||||||
| 	private static final Logger LOGGER = LogManager.getLogger("CustomWindowTitle"); |  | ||||||
| 	 |  | ||||||
| 	private IconChanger() {} |  | ||||||
| 	 |  | ||||||
| 	public static void setIcon(Path iconPath) { |  | ||||||
| 		long windowHandle = Minecraft.getInstance().getWindow().getWindow(); |  | ||||||
| 		setWindowIcon(windowHandle, iconPath); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static void setWindowIcon(long windowHandle, Path iconPath) { |  | ||||||
| 		ByteBuffer icon = null; |  | ||||||
| 		try (MemoryStack stack = MemoryStack.stackPush()) { |  | ||||||
| 			IntBuffer w = stack.mallocInt(1); |  | ||||||
| 			IntBuffer h = stack.mallocInt(1); |  | ||||||
| 			IntBuffer channels = stack.mallocInt(1); |  | ||||||
| 			 |  | ||||||
| 			icon = loadIcon(iconPath, w, h, channels); |  | ||||||
| 			if (icon == null) { |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			try (GLFWImage.Buffer icons = GLFWImage.malloc(1)) { |  | ||||||
| 				GLFWImage iconImage = icons.get(0); |  | ||||||
| 				iconImage.set(w.get(0), h.get(0), icon); |  | ||||||
| 				 |  | ||||||
| 				GLFW.glfwSetWindowIcon(windowHandle, icons); |  | ||||||
| 			} |  | ||||||
| 		} catch (Exception e) { |  | ||||||
| 			LOGGER.error("Failed to set window icon from path: {}", iconPath, e); |  | ||||||
| 		} finally { |  | ||||||
| 			if (icon != null) { |  | ||||||
| 				STBImage.stbi_image_free(icon); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static ByteBuffer loadIcon(Path path, IntBuffer w, IntBuffer h, IntBuffer channels) throws IOException { |  | ||||||
| 		byte[] iconBytes = Files.readAllBytes(path); |  | ||||||
| 		 |  | ||||||
| 		ByteBuffer buffer = ByteBuffer.allocateDirect(iconBytes.length).put(iconBytes).flip(); |  | ||||||
| 		ByteBuffer icon = STBImage.stbi_load_from_memory(buffer, w, h, channels, 4); |  | ||||||
| 		 |  | ||||||
| 		if (icon == null) { |  | ||||||
| 			LOGGER.error("Failed to load image from path: {} - {}", path, STBImage.stbi_failure_reason()); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return icon; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| package chylex.customwindowtitle; |  | ||||||
|  |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
|  |  | ||||||
| public final class TitleChanger { |  | ||||||
| 	private TitleChanger() {} |  | ||||||
| 	 |  | ||||||
| 	public static void setTitle(TitleConfig config) { |  | ||||||
| 		Minecraft.getInstance().getWindow().setTitle(TitleParser.parse(config.getTitle())); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,127 +0,0 @@ | |||||||
| package chylex.customwindowtitle; |  | ||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableMap; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.nio.charset.StandardCharsets; |  | ||||||
| import java.nio.file.Files; |  | ||||||
| import java.nio.file.Path; |  | ||||||
| import java.nio.file.Paths; |  | ||||||
| import java.util.LinkedHashMap; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| public final class TitleConfig { |  | ||||||
| 	private static final String KEY_TITLE = "title"; |  | ||||||
| 	private static final String KEY_ICON = "icon"; |  | ||||||
| 	 |  | ||||||
| 	private static final ImmutableMap<String, String> DEFAULTS = ImmutableMap.<String, String>builder() |  | ||||||
| 		.put(KEY_TITLE, "Minecraft {mcversion}") |  | ||||||
| 		.put(KEY_ICON, "") |  | ||||||
| 		.buildOrThrow(); |  | ||||||
| 	 |  | ||||||
| 	private static volatile TitleConfig instance; |  | ||||||
| 	 |  | ||||||
| 	public static TitleConfig getInstance() { |  | ||||||
| 		return instance; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static TitleConfig load(String folder) { |  | ||||||
| 		if (instance != null) { |  | ||||||
| 			throw new IllegalStateException("TitleConfig has already been loaded and cannot be loaded again."); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		if (instance == null) { |  | ||||||
| 			synchronized(TitleConfig.class) { |  | ||||||
| 				if (instance == null) { |  | ||||||
| 					instance = loadImpl(folder); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return instance; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static TitleConfig loadImpl(String folder) { |  | ||||||
| 		Path configFile = Paths.get(folder, "customwindowtitle-client.toml"); |  | ||||||
| 		Map<String, String> config = new LinkedHashMap<>(DEFAULTS); |  | ||||||
| 		 |  | ||||||
| 		try { |  | ||||||
| 			if (!Files.exists(configFile)) { |  | ||||||
| 				Files.write(configFile, config.entrySet().stream() |  | ||||||
| 					.map(entry -> String.format("%s = '%s'", entry.getKey(), entry.getValue())) |  | ||||||
| 					.collect(Collectors.toList()), StandardCharsets.UTF_8); |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				Files.readAllLines(configFile, StandardCharsets.UTF_8).stream() |  | ||||||
| 					.map(String::trim) |  | ||||||
| 					.filter(line -> !line.isEmpty()) |  | ||||||
| 					.forEach(line -> { |  | ||||||
| 						String[] split = line.split("=", 2); |  | ||||||
| 						 |  | ||||||
| 						if (split.length != 2) { |  | ||||||
| 							throw new RuntimeException("CustomWindowTitle configuration has an invalid line: " + line); |  | ||||||
| 						} |  | ||||||
| 						 |  | ||||||
| 						String key = split[0].trim(); |  | ||||||
| 						String value = parseTrimmedValue(split[1].trim()); |  | ||||||
| 						 |  | ||||||
| 						if (config.containsKey(key)) { |  | ||||||
| 							config.put(key, value); |  | ||||||
| 						} |  | ||||||
| 						else { |  | ||||||
| 							throw new RuntimeException("CustomWindowTitle configuration has an invalid key: " + key); |  | ||||||
| 						} |  | ||||||
| 					}); |  | ||||||
| 			} |  | ||||||
| 		} catch (IOException e) { |  | ||||||
| 			throw new RuntimeException("CustomWindowTitle configuration error", e); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		String iconPathStr = config.get(KEY_ICON); |  | ||||||
| 		Path iconPath = iconPathStr.isEmpty() ? null : Paths.get(folder, iconPathStr); |  | ||||||
| 		if (iconPath != null && Files.notExists(iconPath)) { |  | ||||||
| 			throw new RuntimeException("CustomWindowTitle configuration points to a missing icon: " + iconPath); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return new TitleConfig(config.get(KEY_TITLE), iconPath); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static String parseTrimmedValue(String value) { |  | ||||||
| 		if (value.isEmpty()) { |  | ||||||
| 			return value; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		final char surrounding = value.charAt(0); |  | ||||||
| 		final int length = value.length(); |  | ||||||
| 		 |  | ||||||
| 		if (value.charAt(length - 1) == surrounding) { |  | ||||||
| 			value = value.substring(1, length - 1); |  | ||||||
| 			 |  | ||||||
| 			if (surrounding == '"') { |  | ||||||
| 				value = value.replace("\\\"", "\"").replace("\\\\", "\\"); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return value; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private final String title; |  | ||||||
| 	private final Path icon; |  | ||||||
| 	 |  | ||||||
| 	private TitleConfig(final String title, final Path icon) { |  | ||||||
| 		this.title = title; |  | ||||||
| 		this.icon = icon; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public String getTitle() { |  | ||||||
| 		return title; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public boolean hasIcon() { |  | ||||||
| 		return icon != null; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public Path getIconPath() { |  | ||||||
| 		return icon; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| package chylex.customwindowtitle; |  | ||||||
|  |  | ||||||
| public class TokenException extends RuntimeException { |  | ||||||
| 	public TokenException(final String message) { |  | ||||||
| 		super(message); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| package chylex.customwindowtitle.data; |  | ||||||
|  |  | ||||||
| import static chylex.customwindowtitle.TitleTokens.noArgs; |  | ||||||
| import static chylex.customwindowtitle.TitleTokens.oneArg; |  | ||||||
| import static chylex.customwindowtitle.TitleTokens.registerToken; |  | ||||||
|  |  | ||||||
| public final class CommonTokenData { |  | ||||||
| 	public static void register(final CommonTokenProvider provider) { |  | ||||||
| 		registerToken("mcversion", noArgs(provider::getMinecraftVersion)); |  | ||||||
| 		registerToken("modversion", oneArg(provider::getModVersion)); |  | ||||||
| 		registerToken("username", noArgs(provider::getUsername)); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private CommonTokenData() {} |  | ||||||
| } |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| package chylex.customwindowtitle.data; |  | ||||||
|  |  | ||||||
| import net.minecraft.SharedConstants; |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
|  |  | ||||||
| public interface CommonTokenProvider { |  | ||||||
| 	default String getMinecraftVersion() { |  | ||||||
| 		return SharedConstants.getCurrentVersion().getName(); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	String getModVersion(final String modId); |  | ||||||
| 	 |  | ||||||
| 	default String getUsername() { |  | ||||||
| 		return Minecraft.getInstance().getUser().getName(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| package chylex.customwindowtitle.mixin; |  | ||||||
|  |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
| import org.spongepowered.asm.mixin.Mixin; |  | ||||||
| import org.spongepowered.asm.mixin.injection.At; |  | ||||||
| import org.spongepowered.asm.mixin.injection.Inject; |  | ||||||
| import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |  | ||||||
|  |  | ||||||
| @Mixin(Minecraft.class) |  | ||||||
| public final class DisableVanillaTitle { |  | ||||||
| 	@Inject(method = "updateTitle()V", at = @At("HEAD"), cancellable = true) |  | ||||||
| 	private void updateTitle(final CallbackInfo info) { |  | ||||||
| 		info.cancel(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| package chylex.customwindowtitle.mixin; |  | ||||||
|  |  | ||||||
| import chylex.customwindowtitle.IconChanger; |  | ||||||
| import chylex.customwindowtitle.TitleConfig; |  | ||||||
| import net.minecraft.client.Minecraft; |  | ||||||
| import org.spongepowered.asm.mixin.Mixin; |  | ||||||
| import org.spongepowered.asm.mixin.injection.At; |  | ||||||
| import org.spongepowered.asm.mixin.injection.Inject; |  | ||||||
| import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |  | ||||||
|  |  | ||||||
| @Mixin(Minecraft.class) |  | ||||||
| public final class InitializeCustomIcon { |  | ||||||
| 	@Inject(method = "onResourceLoadFinished", at = @At("HEAD")) |  | ||||||
| 	private void onFinishedLoading(CallbackInfo callbackInfo) { |  | ||||||
| 		TitleConfig config = TitleConfig.getInstance(); |  | ||||||
| 		if (config != null && config.hasIcon()) { |  | ||||||
| 			IconChanger.setIcon(config.getIconPath()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| { |  | ||||||
|   "required": true, |  | ||||||
|   "minVersion": "0.8", |  | ||||||
|   "package": "chylex.customwindowtitle.mixin", |  | ||||||
|   "refmap": "customwindowtitle.refmap.json", |  | ||||||
|   "compatibilityLevel": "JAVA_17", |  | ||||||
|   "client": [ |  | ||||||
|     "DisableVanillaTitle", |  | ||||||
|     "InitializeCustomIcon" |  | ||||||
|   ], |  | ||||||
|   "injectors": { |  | ||||||
|     "defaultRequire": 1 |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| { |  | ||||||
|     "pack": { |  | ||||||
|         "description": "${name}", |  | ||||||
|         "pack_format": 7, |  | ||||||
|         "_comment": "" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| { |  | ||||||
|   "jars": [{ |  | ||||||
|     "identifier": { |  | ||||||
|       "group": "${group}", |  | ||||||
|       "artifact": "${id}" |  | ||||||
|     }, |  | ||||||
|     "version": { |  | ||||||
|       "artifactVersion": "${version}", |  | ||||||
|       "range": "[${version}]" |  | ||||||
|     }, |  | ||||||
|     "path": "jars/${jarPrefix}-NeoForge.jar" |  | ||||||
|   }] |  | ||||||
| } |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| { |  | ||||||
|   "schemaVersion": 1, |  | ||||||
|   "id": "${id}_multiloader", |  | ||||||
|   "name": "${name} (Multiloader)", |  | ||||||
|   "description": "${description}", |  | ||||||
|   "version": "${version}", |  | ||||||
|   "license": "${license}", |  | ||||||
|    |  | ||||||
|   "authors": [ |  | ||||||
|     "${author}" |  | ||||||
|   ], |  | ||||||
|    |  | ||||||
|   "contact": { |  | ||||||
|     "homepage": "https://chylex.com", |  | ||||||
|     "issues": "${issuesURL}", |  | ||||||
|     "sources": "${sourcesURL}" |  | ||||||
|   }, |  | ||||||
|    |  | ||||||
|   "environment": "${sidesForFabric}", |  | ||||||
|    |  | ||||||
|   "jars": [{ |  | ||||||
|       "file": "jars/${jarPrefix}-Fabric.jar" |  | ||||||
|   }], |  | ||||||
|    |  | ||||||
|   "custom": { |  | ||||||
|     "modmenu": { |  | ||||||
|       "parent": "${id}", |  | ||||||
|       "badges": [ "library" ], |  | ||||||
|       "update_checker": false |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user