diff --git a/.gitignore b/.gitignore
index fb5ce62..a6241a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,15 +4,22 @@ eclipse/
 run/
 out/
 .gradle/
+.idea/$CACHE_FILE$
+.idea/codeStyles/
+.idea/compiler.xml
+.idea/dictionaries
+.idea/inspectionProfiles/
+.idea/jarRepositories.xml
+.idea/libraries/
+.idea/misc.xml
+.idea/modules/
+.idea/modules.xml
+.idea/runConfigurations/
+.idea/shelf/
+.idea/uiDesigner.xml
+.idea/workspace.xml
 .settings/
 .updateclasses/
-.idea/codeStyles/
-.idea/inspectionProfiles/
-.idea/libraries/
-.idea/$CACHE_FILE$
-.idea/dictionaries
-.idea/jarRepositories.xml
-.idea/workspace.xml
 .classpath
 .project
 .DS_Store
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 1eade6a..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel>
-      <module name="Fabric" target="1.8" />
-      <module name="Fabric.main" target="1.8" />
-      <module name="Fabric.test" target="1.8" />
-      <module name="Forge" target="1.8" />
-      <module name="Forge.main" target="1.8" />
-      <module name="Forge.test" target="1.8" />
-    </bytecodeTargetLevel>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 0919a80..bb79189 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -7,20 +7,12 @@
         <option name="delegatedBuild" value="true" />
         <option name="testRunner" value="GRADLE" />
         <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$/Fabric" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleJvm" value="16" />
         <option name="modules">
           <set>
+            <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/Fabric" />
-          </set>
-        </option>
-      </GradleProjectSettings>
-      <GradleProjectSettings>
-        <option name="delegatedBuild" value="true" />
-        <option name="testRunner" value="GRADLE" />
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$/Forge" />
-        <option name="modules">
-          <set>
             <option value="$PROJECT_DIR$/Forge" />
           </set>
         </option>
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index d64da9d..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="EntryPointsManager">
-    <list size="6">
-      <item index="0" class="java.lang.String" itemvalue="net.minecraftforge.eventbus.api.SubscribeEvent" />
-      <item index="1" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod" />
-      <item index="2" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod.EventHandler" />
-      <item index="3" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.Mixin" />
-      <item index="4" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.injection.Inject" />
-      <item index="5" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.eventhandler.SubscribeEvent" />
-    </list>
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 6570c7a..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Fabric.iml" filepath="$PROJECT_DIR$/.idea/modules/Fabric.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Fabric.main.iml" filepath="$PROJECT_DIR$/.idea/modules/Fabric.main.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Fabric.test.iml" filepath="$PROJECT_DIR$/.idea/modules/Fabric.test.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Forge.iml" filepath="$PROJECT_DIR$/.idea/modules/Forge.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Forge.main.iml" filepath="$PROJECT_DIR$/.idea/modules/Forge.main.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/Forge.test.iml" filepath="$PROJECT_DIR$/.idea/modules/Forge.test.iml" />
-      <module fileurl="file://$PROJECT_DIR$/Minecraft-Window-Title.iml" filepath="$PROJECT_DIR$/Minecraft-Window-Title.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/modules/Fabric.iml b/.idea/modules/Fabric.iml
deleted file mode 100644
index a8ebfe8..0000000
--- a/.idea/modules/Fabric.iml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.fabric" externalSystemModuleVersion="v1.1.0" linkedProjectId="Fabric" linkedProjectPath="$MODULE_DIR$/../../Fabric" rootProjectPath="$MODULE_DIR$/../../Fabric" />
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Fabric">
-      <excludeFolder url="file://$MODULE_DIR$/../../Fabric/.gradle" />
-      <excludeFolder url="file://$MODULE_DIR$/../../Fabric/build" />
-      <excludeFolder url="file://$MODULE_DIR$/../../Fabric/run" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/modules/Fabric.main.iml b/.idea/modules/Fabric.main.iml
deleted file mode 100644
index 02ad35a..0000000
--- a/.idea/modules/Fabric.main.iml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.fabric" externalSystemModuleType="sourceSet" externalSystemModuleVersion="v1.1.0" linkedProjectId="Fabric:main" linkedProjectPath="$MODULE_DIR$/../../Fabric" rootProjectPath="$MODULE_DIR$/../../Fabric" />
-  <component name="FacetManager">
-    <facet type="minecraft" name="Minecraft">
-      <configuration>
-        <autoDetectTypes>
-          <platformType>FABRIC</platformType>
-          <platformType>MIXIN</platformType>
-          <platformType>MCP</platformType>
-        </autoDetectTypes>
-      </configuration>
-    </facet>
-  </component>
-  <component name="McpModuleSettings">
-    <option name="srgType" value="SRG" />
-  </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Fabric/src/main">
-      <sourceFolder url="file://$MODULE_DIR$/../../Fabric/src/main/java" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/../../Fabric/src/main/resources" type="java-resource" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module-library" scope="PROVIDED">
-      <library>
-        <CLASSES>
-          <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/net.fabricmc/fabric-loom/0.2.6-SNAPSHOT/c4870a9dea65b47e62686806437c907ccf5f4b65/fabric-loom-0.2.6-SNAPSHOT.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES />
-      </library>
-    </orderEntry>
-    <orderEntry type="module-library">
-      <library>
-        <CLASSES>
-          <root url="jar://$USER_HOME$/.gradle/caches/fabric-loom/yarn-1.15.2+build.1-v2-final.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES />
-      </library>
-    </orderEntry>
-    <orderEntry type="library" name="Gradle: com.mojang:patchy:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: oshi-project:oshi-core:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:jna:4.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:platform:3.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.ibm.icu:icu4j-core-mojang:51.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:javabridge:1.0.22" level="project" />
-    <orderEntry type="library" name="Gradle: net.sf.jopt-simple:jopt-simple:5.0.3" level="project" />
-    <orderEntry type="library" name="Gradle: io.netty:netty-all:4.1.25.Final" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.guava:guava:21.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.5" level="project" />
-    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.5" level="project" />
-    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jutils:jutils:1.0.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:brigadier:1.0.17" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:datafixerupper:2.0.24" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:authlib:1.5.25" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-compress:1.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.3.3" level="project" />
-    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.1.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.3.2" level="project" />
-    <orderEntry type="library" name="Gradle: it.unimi.dsi:fastutil:8.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:tiny-mappings-parser:0.2.2.14" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:sponge-mixin:0.8+build.18" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:tiny-remapper:0.2.2.64" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:fabric-loader-sat4j:2.3.5.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.jimfs:jimfs:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-analysis:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-commons:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-tree:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-util:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:minecraft:1.15.2-mapped-net.fabricmc.yarn-1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-api:0.4.29+build.290-1.15@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-api-base:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-biomes-v1:0.1.5+3b05f68e0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-blockrenderlayer-v1:1.1.4+c6a8ea890c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-commands-v0:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-containers-v0:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-content-registries-v0:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-crash-report-info-v1:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-dimensions-v1:0.2.4+203491ea0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-events-interaction-v0:0.2.7+a1bd31180c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-events-lifecycle-v0:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-item-groups-v0:0.1.6+ec40b2e10c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-keybindings-v0:0.1.1+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-loot-tables-v1:0.1.5+e08a73050c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-mining-levels-v0:0.1.1+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-models-v0:0.1.0+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-networking-blockentity-v0:0.2.3+e08a73050c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-networking-v0:0.1.7+12515ed90c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-object-builders-v0:0.1.3+e4c9a9c30c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-particles-v1:0.1.1+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-registry-sync-v0:0.2.6+f3d8141b0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-api-v1:0.2.9+aea78a250c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-indigo:0.2.22+203491ea0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-registries-v1:2.0.1+5a0f9a600c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-data-attachment-v1:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-fluids-v1:0.1.6+12515ed90c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-v0:1.1.0+534104900c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-v1:0.1.0+534104900c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-resource-loader-v0:0.1.10+06c939b30c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-tag-extensions-v0:0.1.3+abd915800c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-textures-v0:1.0.4+821cdba70c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:fabric-loader:0.8.2+build.194@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" scope="RUNTIME" name="Gradle: net.fabricmc:dev-launch-injector:0.2.0+build.6" level="project" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/modules/Fabric.test.iml b/.idea/modules/Fabric.test.iml
deleted file mode 100644
index d4450ae..0000000
--- a/.idea/modules/Fabric.test.iml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.fabric" externalSystemModuleType="sourceSet" externalSystemModuleVersion="v1.1.0" linkedProjectId="Fabric:test" linkedProjectPath="$MODULE_DIR$/../../Fabric" rootProjectPath="$MODULE_DIR$/../../Fabric" />
-  <component name="FacetManager">
-    <facet type="minecraft" name="Minecraft">
-      <configuration>
-        <autoDetectTypes>
-          <platformType>FABRIC</platformType>
-          <platformType>MIXIN</platformType>
-          <platformType>MCP</platformType>
-        </autoDetectTypes>
-      </configuration>
-    </facet>
-  </component>
-  <component name="McpModuleSettings">
-    <option name="srgType" value="SRG" />
-  </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Fabric/src/test" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="Fabric.main" />
-    <orderEntry type="module-library">
-      <library>
-        <CLASSES>
-          <root url="jar://$USER_HOME$/.gradle/caches/fabric-loom/yarn-1.15.2+build.1-v2-final.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES />
-      </library>
-    </orderEntry>
-    <orderEntry type="library" name="Gradle: com.mojang:patchy:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: oshi-project:oshi-core:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:jna:4.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:platform:3.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.ibm.icu:icu4j-core-mojang:51.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:javabridge:1.0.22" level="project" />
-    <orderEntry type="library" name="Gradle: net.sf.jopt-simple:jopt-simple:5.0.3" level="project" />
-    <orderEntry type="library" name="Gradle: io.netty:netty-all:4.1.25.Final" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.guava:guava:21.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.5" level="project" />
-    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.5" level="project" />
-    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jutils:jutils:1.0.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:brigadier:1.0.17" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:datafixerupper:2.0.24" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:authlib:1.5.25" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-compress:1.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.3.3" level="project" />
-    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.1.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.3.2" level="project" />
-    <orderEntry type="library" name="Gradle: it.unimi.dsi:fastutil:8.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:tiny-mappings-parser:0.2.2.14" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:sponge-mixin:0.8+build.18" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:tiny-remapper:0.2.2.64" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:fabric-loader-sat4j:2.3.5.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.jimfs:jimfs:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-analysis:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-commons:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-tree:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-util:8.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:minecraft:1.15.2-mapped-net.fabricmc.yarn-1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-api:0.4.29+build.290-1.15@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-api-base:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-biomes-v1:0.1.5+3b05f68e0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-blockrenderlayer-v1:1.1.4+c6a8ea890c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-commands-v0:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-containers-v0:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-content-registries-v0:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-crash-report-info-v1:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-dimensions-v1:0.2.4+203491ea0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-events-interaction-v0:0.2.7+a1bd31180c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-events-lifecycle-v0:0.1.2+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-item-groups-v0:0.1.6+ec40b2e10c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-keybindings-v0:0.1.1+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-loot-tables-v1:0.1.5+e08a73050c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-mining-levels-v0:0.1.1+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-models-v0:0.1.0+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-networking-blockentity-v0:0.2.3+e08a73050c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-networking-v0:0.1.7+12515ed90c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-object-builders-v0:0.1.3+e4c9a9c30c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-particles-v1:0.1.1+dfdb52d60c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-registry-sync-v0:0.2.6+f3d8141b0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-api-v1:0.2.9+aea78a250c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-indigo:0.2.22+203491ea0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-renderer-registries-v1:2.0.1+5a0f9a600c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-data-attachment-v1:0.1.3+b7f9825d0c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-fluids-v1:0.1.6+12515ed90c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-v0:1.1.0+534104900c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-rendering-v1:0.1.0+534104900c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-resource-loader-v0:0.1.10+06c939b30c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-tag-extensions-v0:0.1.3+abd915800c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc.fabric-api:fabric-textures-v0:1.0.4+821cdba70c@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" name="Gradle: net.fabricmc:fabric-loader:0.8.2+build.194@net.fabricmc.yarn.1_15_2.1.15.2+build.1-v2" level="project" />
-    <orderEntry type="library" scope="RUNTIME" name="Gradle: net.fabricmc:dev-launch-injector:0.2.0+build.6" level="project" />
-  </component>
-  <component name="TestModuleProperties" production-module="Fabric.main" />
-</module>
\ No newline at end of file
diff --git a/.idea/modules/Forge.iml b/.idea/modules/Forge.iml
deleted file mode 100644
index ec3e5de..0000000
--- a/.idea/modules/Forge.iml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.forge" externalSystemModuleVersion="1.0.2" linkedProjectId="Forge" linkedProjectPath="$MODULE_DIR$/../../Forge" rootProjectPath="$MODULE_DIR$/../../Forge" />
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Forge">
-      <excludeFolder url="file://$MODULE_DIR$/../../Forge/.gradle" />
-      <excludeFolder url="file://$MODULE_DIR$/../../Forge/build" />
-      <excludeFolder url="file://$MODULE_DIR$/../../Forge/run" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/modules/Forge.main.iml b/.idea/modules/Forge.main.iml
deleted file mode 100644
index a339929..0000000
--- a/.idea/modules/Forge.main.iml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.forge" externalSystemModuleType="sourceSet" externalSystemModuleVersion="1.0.2" linkedProjectId="Forge:main" linkedProjectPath="$MODULE_DIR$/../../Forge" rootProjectPath="$MODULE_DIR$/../../Forge" />
-  <component name="FacetManager">
-    <facet type="minecraft" name="Minecraft">
-      <configuration>
-        <autoDetectTypes>
-          <platformType>FORGE</platformType>
-          <platformType>MCP</platformType>
-        </autoDetectTypes>
-      </configuration>
-    </facet>
-  </component>
-  <component name="McpModuleSettings">
-    <option name="mappingFile" value="C:\Projects\Mods\Minecraft-Window-Title\Forge\build\createMcpToSrg\output.tsrg" />
-    <option name="mcpVersion" value="snapshot_20200130-1.15.1" />
-    <option name="minecraftVersion" value="1.15.2" />
-    <option name="srgType" value="TSRG" />
-  </component>
-  <component name="NewModuleRootManager">
-    <output url="file://$MODULE_DIR$/../../Forge/build/classes/java/main" />
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Forge/src/main">
-      <sourceFolder url="file://$MODULE_DIR$/../../Forge/src/main/java" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/../../Forge/src/main/resources" type="java-resource" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forge:1.15.2-31.0.14_mapped_snapshot_20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forge:launcher:1.15.2-31.0.14_mapped_snapshot_20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:client:extra:1.15.2" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:accesstransformers:shadowed:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:eventbus:service:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:coremods:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forgespi:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:modlauncher:5.0.0-milestone.4" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:modlauncher:api:5.0.0-milestone.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:mergetool:api:1.0.9" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:mappings_snapshot:zip:20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-commons:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-tree:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:grossjava9hacks:1.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:unsafe:0.2.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.electronwill.night-config:toml:3.6.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.electronwill.night-config:core:3.6.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline:3.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.maven:maven-artifact:3.6.3" level="project" />
-    <orderEntry type="library" name="Gradle: net.jodah:typetools:0.6.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecrell:terminalconsoleappender:1.2.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.sf.jopt-simple:jopt-simple:5.0.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:patchy:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: oshi-project:oshi-core:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:jna:4.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:platform:3.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.ibm.icu:icu4j-core-mojang:51.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:javabridge:1.0.22" level="project" />
-    <orderEntry type="library" name="Gradle: io.netty:netty-all:4.1.25.Final" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.guava:guava:21.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.5" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.3.3" level="project" />
-    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jutils:jutils:1.0.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:brigadier:1.0.17" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:datafixerupper:2.0.24" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:authlib:1.5.25" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-compress:1.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.1.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.3.2" level="project" />
-    <orderEntry type="library" name="Gradle: it.unimi.dsi:fastutil:8.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:natives-windows:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.antlr:antlr4-runtime:4.7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-util:6.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-analysis:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.codehaus.plexus:plexus-utils:3.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline-reader:3.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-linux:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-osx:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-windows:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline-terminal:3.12.1" level="project" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/modules/Forge.test.iml b/.idea/modules/Forge.test.iml
deleted file mode 100644
index ecb3359..0000000
--- a/.idea/modules/Forge.test.iml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module version="4">
-  <component name="ExternalSystem" externalSystem="GRADLE" externalSystemModuleGroup="chylex.customwindowtitle.forge" externalSystemModuleType="sourceSet" externalSystemModuleVersion="1.0.2" linkedProjectId="Forge:test" linkedProjectPath="$MODULE_DIR$/../../Forge" rootProjectPath="$MODULE_DIR$/../../Forge" />
-  <component name="FacetManager">
-    <facet type="minecraft" name="Minecraft">
-      <configuration>
-        <autoDetectTypes>
-          <platformType>FORGE</platformType>
-          <platformType>MCP</platformType>
-        </autoDetectTypes>
-      </configuration>
-    </facet>
-  </component>
-  <component name="McpModuleSettings">
-    <option name="mappingFile" value="C:\Projects\Mods\Minecraft-Window-Title\Forge\build\createMcpToSrg\output.tsrg" />
-    <option name="mcpVersion" value="snapshot_20200130-1.15.1" />
-    <option name="minecraftVersion" value="1.15.2" />
-    <option name="srgType" value="TSRG" />
-  </component>
-  <component name="NewModuleRootManager">
-    <output-test url="file://$MODULE_DIR$/../../Forge/build/classes/java/test" />
-    <exclude-output />
-    <content url="file://$MODULE_DIR$/../../Forge/src/test">
-      <sourceFolder url="file://$MODULE_DIR$/../../Forge/src/test/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/../../Forge/src/test/resources" type="java-test-resource" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="Forge.main" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forge:1.15.2-31.0.14_mapped_snapshot_20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forge:launcher:1.15.2-31.0.14_mapped_snapshot_20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:client:extra:1.15.2" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:accesstransformers:shadowed:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:eventbus:service:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:coremods:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:forgespi:2.0.0-milestone.1" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:modlauncher:5.0.0-milestone.4" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:modlauncher:api:5.0.0-milestone.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:mergetool:api:1.0.9" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraft:mappings_snapshot:zip:20200130-1.15.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-commons:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-tree:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: cpw.mods:grossjava9hacks:1.1.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecraftforge:unsafe:0.2.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.electronwill.night-config:toml:3.6.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.electronwill.night-config:core:3.6.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline:3.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.maven:maven-artifact:3.6.3" level="project" />
-    <orderEntry type="library" name="Gradle: net.jodah:typetools:0.6.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.minecrell:terminalconsoleappender:1.2.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-core:2.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.logging.log4j:log4j-api:2.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.sf.jopt-simple:jopt-simple:5.0.4" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:patchy:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: oshi-project:oshi-core:1.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:jna:4.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.dev.jna:platform:3.4.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.ibm.icu:icu4j-core-mojang:51.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:javabridge:1.0.22" level="project" />
-    <orderEntry type="library" name="Gradle: io.netty:netty-all:4.1.25.Final" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.guava:guava:21.0" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.5" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.3.3" level="project" />
-    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jutils:jutils:1.0.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:brigadier:1.0.17" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:datafixerupper:2.0.24" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:authlib:1.5.25" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-compress:1.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.1.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.3.2" level="project" />
-    <orderEntry type="library" name="Gradle: it.unimi.dsi:fastutil:8.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-jemalloc:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-openal:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-opengl:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-glfw:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-stb:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl-tinyfd:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.lwjgl:lwjgl:natives-windows:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: com.mojang:text2speech:natives-windows:1.11.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.antlr:antlr4-runtime:4.7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-util:6.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.ow2.asm:asm-analysis:7.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.codehaus.plexus:plexus-utils:3.2.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline-reader:3.12.1" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-linux:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-osx:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: net.java.jinput:jinput-platform:natives-windows:2.0.5" level="project" />
-    <orderEntry type="library" name="Gradle: org.jline:jline-terminal:3.12.1" level="project" />
-  </component>
-  <component name="TestModuleProperties" production-module="Forge.main" />
-</module>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Build___Merge.xml b/.idea/runConfigurations/Build___Merge.xml
deleted file mode 100644
index eefde87..0000000
--- a/.idea/runConfigurations/Build___Merge.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="Build &amp; Merge" type="ShConfigurationType">
-    <option name="INDEPENDENT_SCRIPT_PATH" value="false" />
-    <option name="SCRIPT_PATH" value="$PROJECT_DIR$/BuildMerge.bat" />
-    <option name="SCRIPT_OPTIONS" value="" />
-    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
-    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
-    <option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
-    <option name="INTERPRETER_PATH" value="" />
-    <option name="INTERPRETER_OPTIONS" value="" />
-    <method v="2" />
-  </configuration>
-</component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Fabric__runClient_.xml b/.idea/runConfigurations/Fabric__runClient_.xml
deleted file mode 100644
index 8977623..0000000
--- a/.idea/runConfigurations/Fabric__runClient_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="Fabric [runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
-    <ExternalSystemSettings>
-      <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$/Fabric" />
-      <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
-      <option name="taskDescriptions">
-        <list />
-      </option>
-      <option name="taskNames">
-        <list>
-          <option value="runClient" />
-        </list>
-      </option>
-      <option name="vmOptions" value="" />
-    </ExternalSystemSettings>
-    <GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
-    <method v="2" />
-  </configuration>
-</component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Forge__runClient_.xml b/.idea/runConfigurations/Forge__runClient_.xml
deleted file mode 100644
index a79fce5..0000000
--- a/.idea/runConfigurations/Forge__runClient_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="Forge [runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
-    <ExternalSystemSettings>
-      <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$/Forge" />
-      <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
-      <option name="taskDescriptions">
-        <list />
-      </option>
-      <option name="taskNames">
-        <list>
-          <option value="runClient" />
-        </list>
-      </option>
-      <option name="vmOptions" value="" />
-    </ExternalSystemSettings>
-    <GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
-    <method v="2" />
-  </configuration>
-</component>
\ No newline at end of file
diff --git a/BuildMerge.bat b/BuildMerge.bat
deleted file mode 100644
index c188534..0000000
--- a/BuildMerge.bat
+++ /dev/null
@@ -1 +0,0 @@
-python BuildMerge.py
diff --git a/BuildMerge.py b/BuildMerge.py
deleted file mode 100644
index f20ab59..0000000
--- a/BuildMerge.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import subprocess
-import platform
-import sys
-import os
-import time
-import shutil
-import zipfile
-
-root = os.path.abspath(sys.path[0])
-builds = os.path.join(root, "Build")
-combined = os.path.join(builds, "Combined")
-outputjar = "CustomWindowTitle.jar"
-
-gradlew = "gradlew.bat" if platform.system() == "Windows" else "gradlew"
-
-def build(folder):
-    separator = "========={}".format("=" * len(folder))
-    
-    print(separator)
-    print("Building {}".format(folder))
-    print(separator)
-    
-    libs = os.path.join(root, folder, "build", "libs")
-    shutil.rmtree(libs)
-    
-    os.chdir(os.path.join(root, folder))
-    subprocess.run([gradlew, "build"])
-    
-    for fname in os.listdir(libs):
-        if "-dev" not in fname:
-            global outputjar
-            outputjar = fname
-            
-            jar = os.path.join(builds, "{}.{}".format(folder, fname))
-            shutil.copyfile(os.path.join(libs, fname), jar)
-            
-            jar = zipfile.ZipFile(jar)
-            jar.extractall(combined)
-            jar.close()
-            
-            break
-
-if os.path.isdir(builds):
-    shutil.rmtree(builds)
-    time.sleep(0.25)
-
-os.mkdir(builds)
-os.mkdir(combined)
-
-# Forge must run last to overwrite MANIFEST.MF
-build("Fabric")
-build("Forge")
-
-os.chdir(builds)
-
-with zipfile.ZipFile(outputjar, "w", compression = zipfile.ZIP_DEFLATED, compresslevel = 9) as jar:
-    for root, dirs, files in os.walk(combined):
-        for fname in files:
-            fname = os.path.join(root, fname)
-            fname = os.path.normpath(fname)
-            jar.write(fname, os.path.relpath(fname, combined))
diff --git a/Fabric/.gitignore b/Fabric/.gitignore
deleted file mode 100644
index ce84071..0000000
--- a/Fabric/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.idea/codeStyles/
-.idea/inspectionProfiles/
-.idea/modules/
-.idea/runConfigurations/
-
-.idea/$CACHE_FILE$
-.idea/dictionaries
-.idea/jarRepositories.xml
-.idea/workspace.xml
diff --git a/Fabric/.idea/Fabric.iml b/Fabric/.idea/Fabric.iml
deleted file mode 100644
index 78b2cc5..0000000
--- a/Fabric/.idea/Fabric.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4" />
\ No newline at end of file
diff --git a/Fabric/.idea/compiler.xml b/Fabric/.idea/compiler.xml
deleted file mode 100644
index 8f9f9f4..0000000
--- a/Fabric/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="1.8" />
-  </component>
-</project>
diff --git a/Fabric/.idea/encodings.xml b/Fabric/.idea/encodings.xml
deleted file mode 100644
index c2bae49..0000000
--- a/Fabric/.idea/encodings.xml
+++ /dev/null
@@ -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>
\ No newline at end of file
diff --git a/Fabric/.idea/gradle.xml b/Fabric/.idea/gradle.xml
deleted file mode 100644
index f2d2e3c..0000000
--- a/Fabric/.idea/gradle.xml
+++ /dev/null
@@ -1,22 +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="delegatedBuild" value="true" />
-        <option name="testRunner" value="GRADLE" />
-        <option name="disableWrapperSourceDistributionNotification" value="true" />
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="gradleJvm" value="1.8" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-          </set>
-        </option>
-        <option name="useQualifiedModuleNames" value="true" />
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
diff --git a/Fabric/.idea/misc.xml b/Fabric/.idea/misc.xml
deleted file mode 100644
index 43bb802..0000000
--- a/Fabric/.idea/misc.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="EntryPointsManager">
-    <list size="5">
-      <item index="0" class="java.lang.String" itemvalue="net.minecraftforge.eventbus.api.SubscribeEvent" />
-      <item index="1" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod" />
-      <item index="2" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod.EventHandler" />
-      <item index="3" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.Mixin" />
-      <item index="4" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.injection.Inject" />
-    </list>
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
-</project>
diff --git a/Fabric/.idea/vcs.xml b/Fabric/.idea/vcs.xml
deleted file mode 100644
index 6c0b863..0000000
--- a/Fabric/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/Fabric/build.gradle b/Fabric/build.gradle
deleted file mode 100644
index 0150b7d..0000000
--- a/Fabric/build.gradle
+++ /dev/null
@@ -1,47 +0,0 @@
-plugins{
-	id 'fabric-loom' version '0.2.6-SNAPSHOT'
-	id 'maven-publish'
-}
-
-sourceCompatibility = JavaVersion.VERSION_1_8
-targetCompatibility = JavaVersion.VERSION_1_8
-
-archivesBaseName = project.archives_base_name
-version = project.mod_version
-group = project.maven_group
-
-minecraft{}
-
-dependencies{
-	minecraft "com.mojang:minecraft:${project.minecraft_version}"
-	mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
-	modCompile "net.fabricmc:fabric-loader:${project.loader_version}"
-	modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
-}
-
-processResources{
-	inputs.property "version", project.version
-
-	from(sourceSets.main.resources.srcDirs){
-		include "fabric.mod.json"
-		expand "version": project.version
-	}
-
-	from(sourceSets.main.resources.srcDirs){
-		exclude "fabric.mod.json"
-	}
-}
-
-// fix jar file name
-version = 'v' + version
-
-// ensure that the encoding is set to UTF-8, no matter what the system default is
-// this fixes some edge cases with special characters not displaying correctly
-// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
-tasks.withType(JavaCompile){
-	options.encoding = "UTF-8"
-}
-
-jar{
-	from "../LICENSE"
-}
diff --git a/Fabric/build.gradle.kts b/Fabric/build.gradle.kts
new file mode 100644
index 0000000..08a5617
--- /dev/null
+++ b/Fabric/build.gradle.kts
@@ -0,0 +1,39 @@
+val modId: String by project
+val minecraftVersion: String by project
+val fabricVersion: String by project
+
+plugins {
+	idea
+	id("fabric-loom") version "0.10-SNAPSHOT"
+}
+
+dependencies {
+	minecraft("com.mojang:minecraft:$minecraftVersion")
+	modImplementation("net.fabricmc:fabric-loader:$fabricVersion")
+	mappings(loom.officialMojangMappings())
+}
+
+loom {
+	runs {
+		named("client") {
+			configName = "Fabric Client"
+			client()
+			runDir("../run")
+			ideConfigGenerated(true)
+		}
+	}
+	
+	mixin {
+		add(sourceSets.main.get(), "$modId.refmap.json")
+	}
+}
+
+tasks.processResources {
+	filesMatching("fabric.mod.json") {
+		expand(inputs.properties)
+	}
+}
+
+tasks.remapJar {
+	archiveVersion.set(tasks.jar.get().archiveVersion)
+}
diff --git a/Fabric/gradle.properties b/Fabric/gradle.properties
deleted file mode 100644
index 3d894ce..0000000
--- a/Fabric/gradle.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-# Done to increase the memory available to gradle.
-org.gradle.jvmargs=-Xmx1G
-
-# Fabric Properties
-	# check these on https://fabricmc.net/use
-	minecraft_version=1.15.2
-	yarn_mappings=1.15.2+build.1
-	loader_version=0.7.5+build.178
-
-# Mod Properties
-	mod_version = 1.1.0
-	maven_group = chylex.customwindowtitle.fabric
-	archives_base_name = CustomWindowTitle
-
-# Dependencies
-	# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
-	fabric_version=0.4.29+build.290-1.15
diff --git a/Fabric/gradle/wrapper/gradle-wrapper.properties b/Fabric/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4b7e1f3..0000000
--- a/Fabric/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/Fabric/settings.gradle b/Fabric/settings.gradle
deleted file mode 100644
index 5b60df3..0000000
--- a/Fabric/settings.gradle
+++ /dev/null
@@ -1,10 +0,0 @@
-pluginManagement {
-    repositories {
-        jcenter()
-        maven {
-            name = 'Fabric'
-            url = 'https://maven.fabricmc.net/'
-        }
-        gradlePluginPortal()
-    }
-}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/TitleConfig.java b/Fabric/src/main/java/chylex/customwindowtitle/TitleConfig.java
deleted file mode 100644
index 7d08fa3..0000000
--- a/Fabric/src/main/java/chylex/customwindowtitle/TitleConfig.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package chylex.customwindowtitle;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-public final class TitleConfig{
-	private static final Map<String, String> DEFAULTS;
-	
-	static{
-		final Map<String, String> defaults = new LinkedHashMap<>();
-		
-		defaults.put("title", "Minecraft {mcversion}");
-		defaults.put("icon16", "");
-		defaults.put("icon32", "");
-		
-		DEFAULTS = Collections.unmodifiableMap(defaults);
-	}
-	
-	public static TitleConfig read(final String folder){
-		final Path configFile = Paths.get(folder, "customwindowtitle-client.toml");
-		final 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 -> {
-					final String[] split = line.split("=", 2);
-					
-					if (split.length != 2){
-						throw new RuntimeException("CustomWindowTitle configuration has an invalid line: " + line);
-					}
-					
-					final String key = split[0].trim();
-					final 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(final IOException e){
-			throw new RuntimeException("CustomWindowTitle configuration error", e);
-		}
-		
-		final String icon16 = config.get("icon16");
-		final String icon32 = config.get("icon32");
-		
-		final Path pathIcon16 = icon16.isEmpty() ? null : Paths.get(folder, icon16);
-		final Path pathIcon32 = icon32.isEmpty() ? null : Paths.get(folder, icon32);
-		
-		if ((pathIcon16 == null) != (pathIcon32 == null)){
-			throw new RuntimeException("CustomWindowTitle configuration specifies only one icon, both 'icon16' and 'icon32' must be set.");
-		}
-		
-		if (pathIcon16 != null && Files.notExists(pathIcon16)){
-			throw new RuntimeException("CustomWindowTitle 16x16 icon not found: " + pathIcon16);
-		}
-		
-		if (pathIcon32 != null && Files.notExists(pathIcon32)){
-			throw new RuntimeException("CustomWindowTitle 32x32 icon not found: " + pathIcon32);
-		}
-		
-		return new TitleConfig(config.get("title"), pathIcon16, pathIcon32);
-	}
-	
-	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 icon16;
-	private final Path icon32;
-	
-	private TitleConfig(final String title, final Path icon16, final Path icon32){
-		this.title = title;
-		this.icon16 = icon16;
-		this.icon32 = icon32;
-	}
-	
-	public String getTitle(){
-		return title;
-	}
-	
-	public boolean hasIcon(){
-		return icon16 != null && icon32 != null;
-	}
-	
-	public InputStream readIcon16(){
-		try{
-			return Files.newInputStream(icon16, StandardOpenOption.READ);
-		}catch(final IOException e){
-			throw new RuntimeException("CustomWindowTitle could not open the specified 16x16 icon: " + icon16, e);
-		}
-	}
-	
-	public InputStream readIcon32(){
-		try{
-			return Files.newInputStream(icon32, StandardOpenOption.READ);
-		}catch(final IOException e){
-			throw new RuntimeException("CustomWindowTitle could not open the specified 32x32 icon: " + icon16, e);
-		}
-	}
-}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/TitleParser.java b/Fabric/src/main/java/chylex/customwindowtitle/TitleParser.java
deleted file mode 100644
index 4113227..0000000
--- a/Fabric/src/main/java/chylex/customwindowtitle/TitleParser.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package chylex.customwindowtitle;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public final class TitleParser{
-	private static final Pattern tokenRegex = Pattern.compile("\\{([a-z]+)(?::([^}]+))?}");
-	private static final Logger logger = LogManager.getLogger("CustomWindowTitle");
-	
-	public static String parse(final String input){
-		final StringBuffer buffer = new StringBuffer();
-		final Matcher matcher = tokenRegex.matcher(input);
-		
-		while(matcher.find()){
-			final String token = matcher.group(1);
-			final String[] args = StringUtils.split(matcher.group(2), ',');
-			
-			String result = null;
-			
-			try{
-				result = TitleTokens.getTokenFunction(token).apply(args == null ? ArrayUtils.EMPTY_STRING_ARRAY : args);
-			}catch(final TokenException e){
-				logger.warn("Error processing token '" + token + "': " + e.getMessage());
-			}catch(final Throwable t){
-				logger.warn("Error processing token '" + token + "': " + t.getMessage(), t);
-			}
-			
-			if (result == null){
-				matcher.appendReplacement(buffer, input.substring(matcher.start(), matcher.end()));
-			}
-			else{
-				matcher.appendReplacement(buffer, result);
-			}
-		}
-		
-		matcher.appendTail(buffer);
-		return buffer.toString();
-	}
-	
-	// Static class
-	
-	private TitleParser(){}
-}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/TitleTokens.java b/Fabric/src/main/java/chylex/customwindowtitle/TitleTokens.java
deleted file mode 100644
index 8eab35b..0000000
--- a/Fabric/src/main/java/chylex/customwindowtitle/TitleTokens.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package chylex.customwindowtitle;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
-
-public final class TitleTokens{
-	
-	// Registry
-	
-	private static final Map<String, Function<String[], String>> tokenMap = new HashMap<>();
-	
-	public static void registerToken(final String token, final Function<String[], String> processor){
-		tokenMap.putIfAbsent(token, processor);
-	}
-	
-	public static Function<String[], String> getTokenFunction(final String token){
-		return tokenMap.getOrDefault(token, args -> null);
-	}
-	
-	// Arguments
-	
-	public static Function<String[], String> noArgs(final Supplier<String> func){
-		return args -> args.length > 0 ? fail("expected no arguments, got " + args.length) : func.get();
-	}
-	
-	public static Function<String[], String> oneArg(final UnaryOperator<String> func){
-		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){
-		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){
-		throw new TokenException(message);
-	}
-	
-	// Static class
-	
-	private TitleTokens(){}
-}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/TokenException.java b/Fabric/src/main/java/chylex/customwindowtitle/TokenException.java
deleted file mode 100644
index b2ee887..0000000
--- a/Fabric/src/main/java/chylex/customwindowtitle/TokenException.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package chylex.customwindowtitle;
-
-public class TokenException extends RuntimeException{
-	public TokenException(final String message){
-		super(message);
-	}
-}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/fabric/CustomWindowTitle.java b/Fabric/src/main/java/chylex/customwindowtitle/fabric/CustomWindowTitle.java
index 3369829..f86137d 100644
--- a/Fabric/src/main/java/chylex/customwindowtitle/fabric/CustomWindowTitle.java
+++ b/Fabric/src/main/java/chylex/customwindowtitle/fabric/CustomWindowTitle.java
@@ -1,29 +1,29 @@
 package chylex.customwindowtitle.fabric;
 import chylex.customwindowtitle.TitleConfig;
 import chylex.customwindowtitle.TitleParser;
+import com.mojang.blaze3d.platform.Window;
 import net.fabricmc.api.ClientModInitializer;
 import net.fabricmc.loader.api.FabricLoader;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.util.Window;
+import net.minecraft.client.Minecraft;
 
-public class CustomWindowTitle implements ClientModInitializer{
+public class CustomWindowTitle implements ClientModInitializer {
 	private final TitleConfig config;
 	
-	public CustomWindowTitle(){
+	public CustomWindowTitle() {
 		config = TitleConfig.read(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath());
 	}
 	
 	@Override
-	public void onInitializeClient(){
+	public void onInitializeClient() {
 		TokenData.register();
-		MinecraftClient.getInstance().execute(this::updateTitle);
+		Minecraft.getInstance().execute(this::updateTitle);
 	}
 	
-	private void updateTitle(){
-		final Window window = MinecraftClient.getInstance().getWindow();
+	private void updateTitle() {
+		final Window window = Minecraft.getInstance().getWindow();
 		window.setTitle(TitleParser.parse(config.getTitle()));
 		
-		if (config.hasIcon()){
+		if (config.hasIcon()) {
 			window.setIcon(config.readIcon16(), config.readIcon32());
 		}
 	}
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/fabric/TokenData.java b/Fabric/src/main/java/chylex/customwindowtitle/fabric/TokenData.java
index 69483d1..1345d52 100644
--- a/Fabric/src/main/java/chylex/customwindowtitle/fabric/TokenData.java
+++ b/Fabric/src/main/java/chylex/customwindowtitle/fabric/TokenData.java
@@ -6,17 +6,17 @@ import static chylex.customwindowtitle.TitleTokens.noArgs;
 import static chylex.customwindowtitle.TitleTokens.oneArg;
 import static chylex.customwindowtitle.TitleTokens.registerToken;
 
-final class TokenData{
-	static void register(){
+final class TokenData {
+	static void register() {
 		registerToken("mcversion", noArgs(TokenData::getMinecraftVersion));
 		registerToken("modversion", oneArg(TokenData::getModVersion));
 	}
 	
-	static String getMinecraftVersion(){
-		return SharedConstants.getGameVersion().getName();
+	static String getMinecraftVersion() {
+		return SharedConstants.getCurrentVersion().getName();
 	}
 	
-	static String getModVersion(final String modId){
+	static String getModVersion(final String modId) {
 		return FabricLoader.getInstance().getModContainer(modId).orElseThrow(() -> new TokenException("mod info for '" + modId + "' not found")).getMetadata().getVersion().getFriendlyString();
 	}
 }
diff --git a/Fabric/src/main/java/chylex/customwindowtitle/fabric/mixin/DisableVanillaTitle.java b/Fabric/src/main/java/chylex/customwindowtitle/fabric/mixin/DisableVanillaTitle.java
deleted file mode 100644
index 34a268e..0000000
--- a/Fabric/src/main/java/chylex/customwindowtitle/fabric/mixin/DisableVanillaTitle.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package chylex.customwindowtitle.fabric.mixin;
-import net.minecraft.client.MinecraftClient;
-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(MinecraftClient.class)
-public final class DisableVanillaTitle{
-	@Inject(method = "updateWindowTitle()V", at = @At("HEAD"), cancellable = true)
-	private void updateTitle(final CallbackInfo info){
-		info.cancel();
-	}
-}
diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json
index 3d4ac03..26f82ae 100644
--- a/Fabric/src/main/resources/fabric.mod.json
+++ b/Fabric/src/main/resources/fabric.mod.json
@@ -2,7 +2,7 @@
   "schemaVersion": 1,
   "id": "customwindowtitle",
   "version": "${version}",
-
+  
   "name": "Custom Window Title",
   "authors": [
     "chylex"
@@ -12,9 +12,9 @@
     "sources": "https://github.com/chylex/Minecraft-Window-Title",
     "issues": "https://github.com/chylex/Minecraft-Window-Title/issues"
   },
-
+  
   "license": "Unlicense",
-
+  
   "environment": "client",
   "entrypoints": {
     "client": [
@@ -22,9 +22,9 @@
     ]
   },
   "mixins": [
-    "mixins.json"
+    "customwindowtitle.mixins.json"
   ],
-
+  
   "depends": {
     "fabricloader": ">=0.7.2",
     "minecraft": ">=1.15"
diff --git a/Forge/.gitignore b/Forge/.gitignore
deleted file mode 100644
index ce84071..0000000
--- a/Forge/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.idea/codeStyles/
-.idea/inspectionProfiles/
-.idea/modules/
-.idea/runConfigurations/
-
-.idea/$CACHE_FILE$
-.idea/dictionaries
-.idea/jarRepositories.xml
-.idea/workspace.xml
diff --git a/Forge/.idea/Forge.iml b/Forge/.idea/Forge.iml
deleted file mode 100644
index 78b2cc5..0000000
--- a/Forge/.idea/Forge.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4" />
\ No newline at end of file
diff --git a/Forge/.idea/compiler.xml b/Forge/.idea/compiler.xml
deleted file mode 100644
index 61a9130..0000000
--- a/Forge/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="1.8" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/Forge/.idea/encodings.xml b/Forge/.idea/encodings.xml
deleted file mode 100644
index c2bae49..0000000
--- a/Forge/.idea/encodings.xml
+++ /dev/null
@@ -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>
\ No newline at end of file
diff --git a/Forge/.idea/gradle.xml b/Forge/.idea/gradle.xml
deleted file mode 100644
index 6e37879..0000000
--- a/Forge/.idea/gradle.xml
+++ /dev/null
@@ -1,22 +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="delegatedBuild" value="true" />
-        <option name="testRunner" value="GRADLE" />
-        <option name="disableWrapperSourceDistributionNotification" value="true" />
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="gradleJvm" value="1.8" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-          </set>
-        </option>
-        <option name="useQualifiedModuleNames" value="true" />
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/Forge/.idea/misc.xml b/Forge/.idea/misc.xml
deleted file mode 100644
index 43bb802..0000000
--- a/Forge/.idea/misc.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="EntryPointsManager">
-    <list size="5">
-      <item index="0" class="java.lang.String" itemvalue="net.minecraftforge.eventbus.api.SubscribeEvent" />
-      <item index="1" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod" />
-      <item index="2" class="java.lang.String" itemvalue="net.minecraftforge.fml.common.Mod.EventHandler" />
-      <item index="3" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.Mixin" />
-      <item index="4" class="java.lang.String" itemvalue="org.spongepowered.asm.mixin.injection.Inject" />
-    </list>
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
-</project>
diff --git a/Forge/.idea/vcs.xml b/Forge/.idea/vcs.xml
deleted file mode 100644
index 6c0b863..0000000
--- a/Forge/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/Forge/build.gradle b/Forge/build.gradle
deleted file mode 100644
index 848cb09..0000000
--- a/Forge/build.gradle
+++ /dev/null
@@ -1,82 +0,0 @@
-buildscript{
-    repositories{
-        maven{ url = 'https://files.minecraftforge.net/maven' }
-        jcenter()
-        mavenCentral()
-    }
-
-    dependencies{
-        classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
-    }
-}
-
-apply plugin: 'net.minecraftforge.gradle'
-apply plugin: 'eclipse'
-
-def mcversion = "1.15.2"
-def forgeversion = "31.0.14"
-
-def prefixName = 'displayName = '
-def prefixVersion = 'version = '
-
-def metaLines = file('src/main/resources/META-INF/mods.toml').readLines()
-def metaName = metaLines.find { line -> line.startsWith(prefixName) }.substring(prefixName.length())[1..-2]
-def metaVersion = metaLines.find { line -> line.startsWith(prefixVersion) }.substring(prefixVersion.length())[1..-2]
-
-group = 'chylex.customwindowtitle.forge'
-version = metaVersion
-archivesBaseName = metaName.replaceAll('\\s', '')
-
-sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
-
-minecraft{
-    mappings channel: 'snapshot', version: '20200130-1.15.1'
-
-    runs{
-        client{
-            workingDirectory file('run')
-
-            mods{
-                customwindowtitle{
-                    source sourceSets.main
-                }
-            }
-        }
-
-        server{
-            workingDirectory file('run')
-
-            mods{
-                customwindowtitle{
-                    source sourceSets.main
-                }
-            }
-        }
-    }
-}
-
-dependencies{
-    minecraft 'net.minecraftforge:forge:' + mcversion + '-' + forgeversion
-}
-
-jar{
-    archiveName = archivesBaseName + '-1.15+v' + version + '.jar'
-
-    from('../'){
-        include 'LICENSE'
-    }
-
-    manifest{
-        attributes([
-                'Specification-Title'  : 'customwindowtitle',
-                'Specification-Version': '1',
-                'Specification-Vendor' : 'chylex',
-
-                'Implementation-Title'  : metaName,
-                'Implementation-Version': metaVersion,
-                'Implementation-Vendor' : 'chylex',
-
-                'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
-        ])
-    }
-}
diff --git a/Forge/build.gradle.kts b/Forge/build.gradle.kts
new file mode 100644
index 0000000..0cdb340
--- /dev/null
+++ b/Forge/build.gradle.kts
@@ -0,0 +1,78 @@
+import net.minecraftforge.gradle.userdev.UserDevExtension
+import org.gradle.api.file.DuplicatesStrategy.INCLUDE
+import org.spongepowered.asm.gradle.plugins.MixinExtension
+
+val modId: String by project
+val minecraftVersion: String by project
+val forgeVersion: String by project
+val mixinVersion: String by project
+
+buildscript {
+	repositories {
+		maven("https://maven.minecraftforge.net")
+		maven("https://repo.spongepowered.org/maven")
+		mavenCentral()
+	}
+	
+	dependencies {
+		classpath(group = "net.minecraftforge.gradle", name = "ForgeGradle", version = "5.1.+") { isChanging = true }
+		classpath(group = "org.spongepowered", name = "mixingradle", version = "0.7-SNAPSHOT")
+	}
+}
+
+plugins {
+	java
+	eclipse
+}
+
+apply {
+	plugin("net.minecraftforge.gradle")
+	plugin("org.spongepowered.mixin")
+}
+
+dependencies {
+	"minecraft"("net.minecraftforge:forge:$minecraftVersion-$forgeVersion")
+	
+	if (System.getProperty("idea.sync.active") != "true") {
+		annotationProcessor("org.spongepowered:mixin:$mixinVersion:processor")
+	}
+}
+
+configure<UserDevExtension> {
+	mappings("official", minecraftVersion)
+	
+	runs {
+		create("client") {
+			taskName = "Client"
+			workingDirectory(rootProject.file("run"))
+			ideaModule("${rootProject.name}.${project.name}.main")
+			
+			property("mixin.env.remapRefMap", "true")
+			property("mixin.env.refMapRemappingFile", "$projectDir/build/createSrgToMcp/output.srg")
+			arg("-mixin.config=$modId.mixins.json")
+			
+			mods {
+				create(modId) {
+					source(sourceSets.main.get())
+					source(rootProject.sourceSets.main.get())
+				}
+			}
+		}
+	}
+}
+
+configure<MixinExtension> {
+	add(sourceSets.main.get(), "$modId.refmap.json")
+}
+
+tasks.processResources {
+	from(sourceSets.main.get().resources.srcDirs) {
+		include("META-INF/mods.toml")
+		expand(inputs.properties)
+		duplicatesStrategy = INCLUDE
+	}
+}
+
+tasks.jar {
+	finalizedBy("reobfJar")
+}
diff --git a/Forge/gradle.properties b/Forge/gradle.properties
deleted file mode 100644
index 878bf1f..0000000
--- a/Forge/gradle.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-# 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
\ No newline at end of file
diff --git a/Forge/gradle/wrapper/gradle-wrapper.jar b/Forge/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 7a3265e..0000000
Binary files a/Forge/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/Forge/gradlew b/Forge/gradlew
deleted file mode 100644
index cccdd3d..0000000
--- a/Forge/gradlew
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/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" "$@"
diff --git a/Forge/gradlew.bat b/Forge/gradlew.bat
deleted file mode 100644
index f955316..0000000
--- a/Forge/gradlew.bat
+++ /dev/null
@@ -1,84 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@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=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-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
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%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
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/Forge/src/main/java/chylex/customwindowtitle/TokenException.java b/Forge/src/main/java/chylex/customwindowtitle/TokenException.java
deleted file mode 100644
index b2ee887..0000000
--- a/Forge/src/main/java/chylex/customwindowtitle/TokenException.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package chylex.customwindowtitle;
-
-public class TokenException extends RuntimeException{
-	public TokenException(final String message){
-		super(message);
-	}
-}
diff --git a/Forge/src/main/java/chylex/customwindowtitle/forge/CustomWindowTitle.java b/Forge/src/main/java/chylex/customwindowtitle/forge/CustomWindowTitle.java
index 760e512..a659c6a 100644
--- a/Forge/src/main/java/chylex/customwindowtitle/forge/CustomWindowTitle.java
+++ b/Forge/src/main/java/chylex/customwindowtitle/forge/CustomWindowTitle.java
@@ -10,26 +10,26 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
 import net.minecraftforge.fml.loading.FMLPaths;
 
 @Mod("customwindowtitle")
-public class CustomWindowTitle{
+public class CustomWindowTitle {
 	private final TitleConfig config;
 	
-	public CustomWindowTitle(){
+	public CustomWindowTitle() {
 		config = TitleConfig.read(FMLPaths.CONFIGDIR.get().toString());
-		FMLJavaModLoadingContext.get().getModEventBus().register(this);
+		FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup);
 		TokenData.register();
 	}
 	
 	@SubscribeEvent
-	public void onClientSetup(final FMLClientSetupEvent e){
+	public void onClientSetup(final FMLClientSetupEvent e) {
 		e.getMinecraftSupplier().get().execute(this::updateTitle);
 	}
 	
-	private void updateTitle(){
-		final MainWindow window = Minecraft.getInstance().getMainWindow();
-		window.func_230148_b_(TitleParser.parse(config.getTitle()));
+	private void updateTitle() {
+		final MainWindow window = Minecraft.getInstance().getWindow();
+		window.setTitle(TitleParser.parse(config.getTitle()));
 		
-		if (config.hasIcon()){
-			window.setWindowIcon(config.readIcon16(), config.readIcon32());
+		if (config.hasIcon()) {
+			window.setIcon(config.readIcon16(), config.readIcon32());
 		}
 	}
 }
diff --git a/Forge/src/main/java/chylex/customwindowtitle/forge/TokenData.java b/Forge/src/main/java/chylex/customwindowtitle/forge/TokenData.java
index 71cb1a8..aa263e6 100644
--- a/Forge/src/main/java/chylex/customwindowtitle/forge/TokenData.java
+++ b/Forge/src/main/java/chylex/customwindowtitle/forge/TokenData.java
@@ -8,25 +8,25 @@ import static chylex.customwindowtitle.TitleTokens.noArgs;
 import static chylex.customwindowtitle.TitleTokens.oneArg;
 import static chylex.customwindowtitle.TitleTokens.registerToken;
 
-final class TokenData{
-	static void register(){
+final class TokenData {
+	static void register() {
 		registerToken("mcversion", noArgs(TokenData::getMinecraftVersion));
 		registerToken("modversion", oneArg(TokenData::getModVersion));
 	}
 	
-	static String getMinecraftVersion(){
-		return SharedConstants.getVersion().getName();
+	static String getMinecraftVersion() {
+		return SharedConstants.getCurrentVersion().getName();
 	}
 	
-	static String getModVersion(final String modId){
+	static String getModVersion(final String modId) {
 		final ModFileInfo file = ModList.get().getModFileById(modId);
 		
-		if (file == null){
+		if (file == null) {
 			throw new TokenException("mod file for '" + modId + "' not found");
 		}
 		
-		for(final IModInfo info : file.getMods()){
-			if (info.getModId().equals(modId)){
+		for (final IModInfo info : file.getMods()) {
+			if (info.getModId().equals(modId)) {
 				return info.getVersion().toString();
 			}
 		}
diff --git a/Forge/src/main/resources/META-INF/coremods.json b/Forge/src/main/resources/META-INF/coremods.json
deleted file mode 100644
index f36d62b..0000000
--- a/Forge/src/main/resources/META-INF/coremods.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "CustomWindowTitle": "coremods/main.js"
-}
diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml
index 1836f45..401ae68 100644
--- a/Forge/src/main/resources/META-INF/mods.toml
+++ b/Forge/src/main/resources/META-INF/mods.toml
@@ -21,6 +21,6 @@ side = "CLIENT"
 [[dependencies.customwindowtitle]]
 modId = "forge"
 mandatory = true
-versionRange = "[31,)"
+versionRange = "[31.2.45,)"
 ordering = "NONE"
 side = "CLIENT"
diff --git a/Forge/src/main/resources/coremods/main.js b/Forge/src/main/resources/coremods/main.js
deleted file mode 100644
index 45fe947..0000000
--- a/Forge/src/main/resources/coremods/main.js
+++ /dev/null
@@ -1,19 +0,0 @@
-function initializeCoreMod(){
-    var opcodes = Java.type("org.objectweb.asm.Opcodes");
-    var InsnNode = Java.type("org.objectweb.asm.tree.InsnNode");
-
-    return {
-        "CustomWindowTitle": {
-            "target": {
-                "type": "METHOD",
-                "class": "net.minecraft.client.Minecraft",
-                "methodName": "func_230150_b_",
-                "methodDesc": "()V"
-            },
-            "transformer": function(methodNode){
-                methodNode.instructions.insert(new InsnNode(opcodes.RETURN));
-                return methodNode;
-            }
-        }
-    };
-}
diff --git a/Minecraft-Window-Title.iml b/Minecraft-Window-Title.iml
deleted file mode 100644
index 3c31754..0000000
--- a/Minecraft-Window-Title.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="Fabric" />
-    <orderEntry type="module" module-name="Forge" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/README.md b/README.md
index b1b906a..c5e2197 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,13 @@ title = "Minecraft {mcversion} - Custom Window Title {modversion:customwindowtit
 
 # For Developers
 
-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
+The mod sources are organized into 3 projects:
+- `src/` contains common source files and mixins
+- `Fabric/src/` contains source files specific for Fabric
+- `Forge/src/` contains source files specific for Forge
 
-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.
+The Gradle project provides the following tasks:
+- `setupIdea` generates Minecraft sources and run configurations for IntelliJ IDEA
+- `assemble` creates 2 `.jar` files in the `build/dist` folder - one for Forge, one for Fabric
+
+When building against a Minecraft version that is only supported by one mod loader, open `gradle.properties` and comment or remove either `forgeVersion` or `fabricVersion` to disable them.
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..12146be
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,162 @@
+import org.gradle.api.file.DuplicatesStrategy.EXCLUDE
+import java.text.SimpleDateFormat
+import java.util.Date
+
+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 minecraftVersion: String by project
+val mixinVersion: String by project
+
+val modNameStripped = modName.replace(" ", "")
+val jarVersion = "$minecraftVersion+v$modVersion"
+
+buildscript {
+	repositories {
+		maven("https://repo.spongepowered.org/maven")
+	}
+}
+
+plugins {
+	`java-library`
+	idea
+	id("org.spongepowered.gradle.vanilla") version "0.2.1-SNAPSHOT"
+}
+
+idea {
+	module {
+		excludeDirs.add(file("gradle"))
+		excludeDirs.add(file("run"))
+		
+		if (findProject(":Forge") == null) {
+			excludeDirs.add(file("Forge"))
+		}
+		
+		if (findProject(":Fabric") == null) {
+			excludeDirs.add(file("Fabric"))
+		}
+	}
+}
+
+repositories {
+	maven("https://repo.spongepowered.org/maven")
+	mavenCentral()
+}
+
+dependencies {
+	implementation("org.spongepowered:mixin:$mixinVersion")
+	api("com.google.code.findbugs:jsr305:3.0.2")
+}
+
+base {
+	archivesName.set("$modNameStripped-Common")
+}
+
+minecraft {
+	version(minecraftVersion)
+	runs.clear()
+}
+
+allprojects {
+	group = "com.$modAuthor.$modId"
+	version = modVersion
+	
+	apply(plugin = "java")
+	
+	dependencies {
+		implementation("org.jetbrains:annotations:22.0.0")
+	}
+	
+	tasks.withType<JavaCompile> {
+		options.encoding = "UTF-8"
+		sourceCompatibility = "1.8"
+		targetCompatibility = "1.8"
+	}
+}
+
+subprojects {
+	repositories {
+		maven("https://repo.spongepowered.org/maven")
+	}
+	
+	dependencies {
+		implementation(rootProject)
+	}
+	
+	base {
+		archivesName.set("$modNameStripped-${project.name}")
+	}
+	
+	tasks.withType<JavaCompile> {
+		source({ rootProject.sourceSets.main.get().allSource })
+	}
+	
+	tasks.processResources {
+		from(rootProject.sourceSets.main.get().resources)
+		
+		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)
+	}
+	
+	tasks.jar {
+		archiveVersion.set(jarVersion)
+		
+		from(rootProject.file("LICENSE"))
+		
+		manifest {
+			attributes(
+				"Specification-Title" to modId,
+				"Specification-Vendor" to modAuthor,
+				"Specification-Version" to "1",
+				"Implementation-Title" to "$modNameStripped-${project.name}",
+				"Implementation-Vendor" to modAuthor,
+				"Implementation-Version" to modVersion,
+				"Implementation-Timestamp" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(Date()),
+				"MixinConfigs" to "$modId.mixins.json"
+			)
+		}
+	}
+}
+
+tasks.register("setupIdea") {
+	group = "mod"
+	
+	dependsOn(tasks.findByName("decompile"))
+	
+	val forge = findProject(":Forge")
+	if (forge != null) {
+		dependsOn(forge.tasks.getByName("genIntellijRuns"))
+	}
+	
+	val fabric = findProject(":Fabric")
+	if (fabric != null) {
+		dependsOn(fabric.tasks.getByName("genSources"))
+	}
+}
+
+val copyJars = tasks.register<Copy>("copyJars") {
+	group = "build"
+	duplicatesStrategy = EXCLUDE
+	
+	for (subproject in subprojects) {
+		dependsOn(subproject.tasks.assemble)
+		from(subproject.base.libsDirectory.file("${subproject.base.archivesName.get()}-$jarVersion.jar"))
+	}
+	
+	into(file("${project.buildDir}/dist"))
+}
+
+tasks.assemble {
+	finalizedBy(copyJars)
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..b18b9e8
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,19 @@
+# Mod
+modId=customwindowtitle
+modName=Custom Window Title
+modDescription=
+modAuthor=chylex
+modVersion=1.1.0
+modLicense=Unlicense
+modSourcesURL=https://github.com/chylex/Minecraft-Window-Title
+modIssuesURL=https://github.com/chylex/Minecraft-Window-Title/issues
+
+# Dependencies
+minecraftVersion=1.16.5
+forgeVersion=36.2.0
+fabricVersion=0.12.5
+mixinVersion=0.8.4
+
+# Gradle
+org.gradle.jvmargs=-Xmx3G
+org.gradle.daemon=false
diff --git a/Fabric/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
similarity index 51%
rename from Fabric/gradle/wrapper/gradle-wrapper.jar
rename to gradle/wrapper/gradle-wrapper.jar
index 5c2d1cf..7454180 100644
Binary files a/Fabric/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Forge/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
similarity index 93%
rename from Forge/gradle/wrapper/gradle-wrapper.properties
rename to gradle/wrapper/gradle-wrapper.properties
index 949819d..ffed3a2 100644
--- a/Forge/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
diff --git a/Fabric/gradlew b/gradlew
similarity index 76%
rename from Fabric/gradlew
rename to gradlew
index 8e25e6c..b4f908a 100644
--- a/Fabric/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env sh
+#!/usr/bin/env bash
 
 #
 # Copyright 2015 the original author or authors.
@@ -72,7 +72,7 @@ case "`uname`" in
   Darwin* )
     darwin=true
     ;;
-  MINGW* )
+  MSYS* | MINGW* )
     msys=true
     ;;
   NONSTOP* )
@@ -82,6 +82,7 @@ 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
@@ -125,10 +126,11 @@ 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
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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
@@ -154,35 +156,28 @@ if $cygwin ; then
         else
             eval `echo args$i`="\"$arg\""
         fi
-        i=$((i+1))
+        i=`expr $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" ;;
+        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 "$@")
+ARGV=("$@")
+eval set -- $DEFAULT_JVM_OPTS
 
-# 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"
+IFS=$'
+' read -rd '' -a JAVA_OPTS_ARR <<< "$(echo $JAVA_OPTS | xargs -n1)"
+IFS=$'
+' read -rd '' -a GRADLE_OPTS_ARR <<< "$(echo $GRADLE_OPTS | xargs -n1)"
 
-# 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" "$@"
+exec "$JAVACMD" "$@" "${JAVA_OPTS_ARR[@]}" "${GRADLE_OPTS_ARR[@]}" "-Dorg.gradle.appname=$APP_BASE_NAME" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "${ARGV[@]}"
diff --git a/Fabric/gradlew.bat b/gradlew.bat
similarity index 86%
rename from Fabric/gradlew.bat
rename to gradlew.bat
index 9618d8d..107acd3 100644
--- a/Fabric/gradlew.bat
+++ b/gradlew.bat
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
 set APP_BASE_NAME=%~n0
 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.
 set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
 set JAVA_HOME=%JAVA_HOME:"=%
 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
 
 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
 @rem Setup the command line
 
 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
+
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
 
 :end
 @rem End local scope for the variables with windows NT shell
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..3084b0e
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,17 @@
+rootProject.name = "Minecraft-Window-Title"
+
+pluginManagement {
+	repositories {
+		gradlePluginPortal()
+		maven(url = "https://maven.fabricmc.net/") { name = "Fabric" }
+		maven(url = "https://repo.spongepowered.org/repository/maven-public/") { name = "Sponge Snapshots" }
+	}
+}
+
+if (settings.extra.has("forgeVersion")) {
+	include("Forge")
+}
+
+if (settings.extra.has("fabricVersion")) {
+	include("Fabric")
+}
diff --git a/Forge/src/main/java/chylex/customwindowtitle/TitleConfig.java b/src/main/java/chylex/customwindowtitle/TitleConfig.java
similarity index 79%
rename from Forge/src/main/java/chylex/customwindowtitle/TitleConfig.java
rename to src/main/java/chylex/customwindowtitle/TitleConfig.java
index 7d08fa3..6525989 100644
--- a/Forge/src/main/java/chylex/customwindowtitle/TitleConfig.java
+++ b/src/main/java/chylex/customwindowtitle/TitleConfig.java
@@ -7,15 +7,14 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardOpenOption;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-public final class TitleConfig{
+public final class TitleConfig {
 	private static final Map<String, String> DEFAULTS;
 	
-	static{
+	static {
 		final Map<String, String> defaults = new LinkedHashMap<>();
 		
 		defaults.put("title", "Minecraft {mcversion}");
@@ -25,34 +24,34 @@ public final class TitleConfig{
 		DEFAULTS = Collections.unmodifiableMap(defaults);
 	}
 	
-	public static TitleConfig read(final String folder){
+	public static TitleConfig read(final String folder) {
 		final Path configFile = Paths.get(folder, "customwindowtitle-client.toml");
 		final Map<String, String> config = new LinkedHashMap<>(DEFAULTS);
 		
-		try{
-			if (!Files.exists(configFile)){
+		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{
+			else {
 				Files.readAllLines(configFile, StandardCharsets.UTF_8).stream().map(String::trim).filter(line -> !line.isEmpty()).forEach(line -> {
 					final String[] split = line.split("=", 2);
 					
-					if (split.length != 2){
+					if (split.length != 2) {
 						throw new RuntimeException("CustomWindowTitle configuration has an invalid line: " + line);
 					}
 					
 					final String key = split[0].trim();
 					final String value = parseTrimmedValue(split[1].trim());
 					
-					if (config.containsKey(key)){
+					if (config.containsKey(key)) {
 						config.put(key, value);
 					}
-					else{
+					else {
 						throw new RuntimeException("CustomWindowTitle configuration has an invalid key: " + key);
 					}
 				});
 			}
-		}catch(final IOException e){
+		} catch (final IOException e) {
 			throw new RuntimeException("CustomWindowTitle configuration error", e);
 		}
 		
@@ -62,33 +61,33 @@ public final class TitleConfig{
 		final Path pathIcon16 = icon16.isEmpty() ? null : Paths.get(folder, icon16);
 		final Path pathIcon32 = icon32.isEmpty() ? null : Paths.get(folder, icon32);
 		
-		if ((pathIcon16 == null) != (pathIcon32 == null)){
+		if ((pathIcon16 == null) != (pathIcon32 == null)) {
 			throw new RuntimeException("CustomWindowTitle configuration specifies only one icon, both 'icon16' and 'icon32' must be set.");
 		}
 		
-		if (pathIcon16 != null && Files.notExists(pathIcon16)){
+		if (pathIcon16 != null && Files.notExists(pathIcon16)) {
 			throw new RuntimeException("CustomWindowTitle 16x16 icon not found: " + pathIcon16);
 		}
 		
-		if (pathIcon32 != null && Files.notExists(pathIcon32)){
+		if (pathIcon32 != null && Files.notExists(pathIcon32)) {
 			throw new RuntimeException("CustomWindowTitle 32x32 icon not found: " + pathIcon32);
 		}
 		
 		return new TitleConfig(config.get("title"), pathIcon16, pathIcon32);
 	}
 	
-	private static String parseTrimmedValue(String value){
-		if (value.isEmpty()){
+	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){
+		if (value.charAt(length - 1) == surrounding) {
 			value = value.substring(1, length - 1);
 			
-			if (surrounding == '"'){
+			if (surrounding == '"') {
 				value = value.replace("\\\"", "\"").replace("\\\\", "\\");
 			}
 		}
@@ -100,32 +99,32 @@ public final class TitleConfig{
 	private final Path icon16;
 	private final Path icon32;
 	
-	private TitleConfig(final String title, final Path icon16, final Path icon32){
+	private TitleConfig(final String title, final Path icon16, final Path icon32) {
 		this.title = title;
 		this.icon16 = icon16;
 		this.icon32 = icon32;
 	}
 	
-	public String getTitle(){
+	public String getTitle() {
 		return title;
 	}
 	
-	public boolean hasIcon(){
+	public boolean hasIcon() {
 		return icon16 != null && icon32 != null;
 	}
 	
-	public InputStream readIcon16(){
-		try{
+	public InputStream readIcon16() {
+		try {
 			return Files.newInputStream(icon16, StandardOpenOption.READ);
-		}catch(final IOException e){
+		} catch (final IOException e) {
 			throw new RuntimeException("CustomWindowTitle could not open the specified 16x16 icon: " + icon16, e);
 		}
 	}
 	
-	public InputStream readIcon32(){
-		try{
+	public InputStream readIcon32() {
+		try {
 			return Files.newInputStream(icon32, StandardOpenOption.READ);
-		}catch(final IOException e){
+		} catch (final IOException e) {
 			throw new RuntimeException("CustomWindowTitle could not open the specified 32x32 icon: " + icon16, e);
 		}
 	}
diff --git a/Forge/src/main/java/chylex/customwindowtitle/TitleParser.java b/src/main/java/chylex/customwindowtitle/TitleParser.java
similarity index 82%
rename from Forge/src/main/java/chylex/customwindowtitle/TitleParser.java
rename to src/main/java/chylex/customwindowtitle/TitleParser.java
index 4113227..9c3c2d2 100644
--- a/Forge/src/main/java/chylex/customwindowtitle/TitleParser.java
+++ b/src/main/java/chylex/customwindowtitle/TitleParser.java
@@ -6,32 +6,32 @@ import org.apache.logging.log4j.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public final class TitleParser{
+public final class TitleParser {
 	private static final Pattern tokenRegex = Pattern.compile("\\{([a-z]+)(?::([^}]+))?}");
 	private static final Logger logger = LogManager.getLogger("CustomWindowTitle");
 	
-	public static String parse(final String input){
+	public static String parse(final String input) {
 		final StringBuffer buffer = new StringBuffer();
 		final Matcher matcher = tokenRegex.matcher(input);
 		
-		while(matcher.find()){
+		while (matcher.find()) {
 			final String token = matcher.group(1);
 			final String[] args = StringUtils.split(matcher.group(2), ',');
 			
 			String result = null;
 			
-			try{
+			try {
 				result = TitleTokens.getTokenFunction(token).apply(args == null ? ArrayUtils.EMPTY_STRING_ARRAY : args);
-			}catch(final TokenException e){
+			} catch (final TokenException e) {
 				logger.warn("Error processing token '" + token + "': " + e.getMessage());
-			}catch(final Throwable t){
+			} catch (final Throwable t) {
 				logger.warn("Error processing token '" + token + "': " + t.getMessage(), t);
 			}
 			
-			if (result == null){
+			if (result == null) {
 				matcher.appendReplacement(buffer, input.substring(matcher.start(), matcher.end()));
 			}
-			else{
+			else {
 				matcher.appendReplacement(buffer, result);
 			}
 		}
@@ -42,5 +42,5 @@ public final class TitleParser{
 	
 	// Static class
 	
-	private TitleParser(){}
+	private TitleParser() {}
 }
diff --git a/Forge/src/main/java/chylex/customwindowtitle/TitleTokens.java b/src/main/java/chylex/customwindowtitle/TitleTokens.java
similarity index 82%
rename from Forge/src/main/java/chylex/customwindowtitle/TitleTokens.java
rename to src/main/java/chylex/customwindowtitle/TitleTokens.java
index 8eab35b..d8c4536 100644
--- a/Forge/src/main/java/chylex/customwindowtitle/TitleTokens.java
+++ b/src/main/java/chylex/customwindowtitle/TitleTokens.java
@@ -5,39 +5,39 @@ import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
 
-public final class TitleTokens{
+public final class TitleTokens {
 	
 	// Registry
 	
 	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(final String token, final Function<String[], String> processor) {
 		tokenMap.putIfAbsent(token, processor);
 	}
 	
-	public static Function<String[], String> getTokenFunction(final String token){
+	public static Function<String[], String> getTokenFunction(final String token) {
 		return tokenMap.getOrDefault(token, args -> null);
 	}
 	
 	// Arguments
 	
-	public static Function<String[], String> noArgs(final Supplier<String> func){
+	public static Function<String[], String> noArgs(final Supplier<String> func) {
 		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(final UnaryOperator<String> func) {
 		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(final int min, final int max, final 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);
 	}
 	
-	private static String fail(final String message){
+	private static String fail(final String message) {
 		throw new TokenException(message);
 	}
 	
 	// Static class
 	
-	private TitleTokens(){}
+	private TitleTokens() {}
 }
diff --git a/src/main/java/chylex/customwindowtitle/TokenException.java b/src/main/java/chylex/customwindowtitle/TokenException.java
new file mode 100644
index 0000000..827156b
--- /dev/null
+++ b/src/main/java/chylex/customwindowtitle/TokenException.java
@@ -0,0 +1,7 @@
+package chylex.customwindowtitle;
+
+public class TokenException extends RuntimeException {
+	public TokenException(final String message) {
+		super(message);
+	}
+}
diff --git a/src/main/java/chylex/customwindowtitle/mixin/DisableVanillaTitle.java b/src/main/java/chylex/customwindowtitle/mixin/DisableVanillaTitle.java
new file mode 100644
index 0000000..0e86cda
--- /dev/null
+++ b/src/main/java/chylex/customwindowtitle/mixin/DisableVanillaTitle.java
@@ -0,0 +1,14 @@
+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();
+	}
+}
diff --git a/Fabric/src/main/resources/mixins.json b/src/main/resources/customwindowtitle.mixins.json
similarity index 56%
rename from Fabric/src/main/resources/mixins.json
rename to src/main/resources/customwindowtitle.mixins.json
index b3f6287..20ac7f1 100644
--- a/Fabric/src/main/resources/mixins.json
+++ b/src/main/resources/customwindowtitle.mixins.json
@@ -1,9 +1,9 @@
 {
   "required": true,
-  "package": "chylex.customwindowtitle.fabric.mixin",
+  "minVersion": "0.8",
+  "package": "chylex.customwindowtitle.mixin",
+  "refmap": "customwindowtitle.refmap.json",
   "compatibilityLevel": "JAVA_8",
-  "mixins": [
-  ],
   "client": [
     "DisableVanillaTitle"
   ],