diff --git a/game/client/build.gradle.kts b/game/client/build.gradle.kts
index 01672dd2a..6f5d97f6e 100644
--- a/game/client/build.gradle.kts
+++ b/game/client/build.gradle.kts
@@ -1,8 +1,20 @@
 import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonArray
+import com.google.gson.JsonElement
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import java.io.BufferedOutputStream
+import java.io.FileOutputStream
+import java.net.URL
+import java.util.zip.ZipEntry
+import java.util.zip.ZipOutputStream
+import kotlin.text.replace
 
 plugins {
     id("java")
     alias(libs.plugins.shadow)
+    id("org.cyclonedx.bom") version ("2.3.1")
 }
 
 group = providers.gradleProperty("bta.group").get()
@@ -10,6 +22,16 @@ version = providers.gradleProperty("bta.version").get()
 val assetPackFormat = providers.gradleProperty("bta.assetPackFormat").get()
 
 val include: Configuration by configurations.creating
+val projects = listOf(":game:core", ":util:seed-viewer", ":util:nbt", ":util:logging")
+
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath("com.google.code.gson:gson:2.13.1")
+    }
+}
 
 repositories {
     mavenCentral()
@@ -31,8 +53,9 @@ dependencies {
     testImplementation("org.junit.jupiter:junit-jupiter")
     // </test dependencies>
 
-    implementation(project(":game:core"))?.let { include(it) }
-    implementation(project(":util:seed-viewer"))?.let { include(it) }
+    for (p in projects) {
+        implementation(project(p))?.let { include(it) }
+    }
     runtimeOnly(project(path = ":util:datagen", configuration = "output"))?.let { include(it) }
 
     // <core dependencies>
@@ -41,8 +64,6 @@ dependencies {
     implementation(libs.gson)?.let { include(it) }
     implementation(libs.brigadier)?.let { include(it) }
     implementation(libs.bundles.log4j)?.let { include(it) }
-    implementation(project(":util:nbt"))?.let { include(it) }
-    implementation(project(":util:logging"))?.let { include(it) }
     // </core dependencies>
 
     implementation("com.github.Better-than-Adventure:legacy-lwjgl3:1.0.6")?.let { include(it) }
@@ -120,6 +141,175 @@ val buildJar by tasks.registering(ShadowJar::class) {
     }
 }
 
+val buildSlimJar by tasks.registering(Jar::class) {
+    mustRunAfter(":util:datagen:runDatagen")
+    dependsOn(":util:datagen:runDatagen")
+    group = "bta"
+//    configurations = listOf(include)
+
+    from(sourceSets.main.get().output.classesDirs)
+    from(sourceSets.main.get().resources)
+
+    archiveFileName = "bta-client.jar"
+    manifest {
+        attributes["Main-Class"] = "net.minecraft.client.Minecraft"
+        attributes["Implementation-Version"] = version
+    }
+
+    // Yoink class files from dependency projects
+    for (p in projects) {
+        val proj = project(p)
+        val sources = File(proj.layout.buildDirectory.get().asFile, "classes/java/main/")
+        from(fileTree(sources).include("**/*.class"))
+        val resources = File(proj.layout.buildDirectory.get().asFile, "resources/main/")
+        from(fileTree(resources).include("**/*.*"))
+    }
+    val proj = project(":util:datagen")
+    val resources = File(proj.layout.buildDirectory.get().asFile, "resources/main/")
+    from(fileTree(resources).include("**/*.*"))
+}
+
+val createInstance by tasks.registering {
+    mustRunAfter(":game:client:buildSlimJar", "cyclonedxBom")
+    dependsOn(":game:client:buildSlimJar", "cyclonedxBom")
+
+    doLast {
+
+        val instanceTemplatesDir = File(layout.projectDirectory.asFile, "instance")
+
+        temporaryDir.deleteRecursively()
+        temporaryDir.mkdirs()
+
+        val versionUnderscored = version.toString().replace(".", "_");
+
+        File(instanceTemplatesDir, "icon.png").copyTo(File(temporaryDir, "v${versionUnderscored}.png"))
+
+        val instanceCFG = File(temporaryDir, "instance.cfg")
+        instanceCFG.createNewFile()
+        instanceCFG.writeText(File(instanceTemplatesDir, "instance.cfg").readText().replace("\$version", versionUnderscored))
+
+        val mmcpackJSON = File(temporaryDir, "mmc-pack.json")
+        mmcpackJSON.createNewFile()
+        mmcpackJSON.writeText(File(instanceTemplatesDir, "mmc-pack.json").readText().replace("\$version", versionUnderscored))
+
+        val pathmapJSON = File(temporaryDir, "pathmap.json")
+        pathmapJSON.createNewFile()
+        pathmapJSON.writeText(File(instanceTemplatesDir, "pathmap.json").readText().replace("\$version", versionUnderscored))
+
+        File(instanceTemplatesDir, "patches/org.lwjgl.json").copyTo(File(temporaryDir, "patches/org.lwjgl.json")) // TODO probably make this autogenerated too at some point
+
+        generateMcPatchesFile(instanceTemplatesDir, temporaryDir, File(layout.buildDirectory.get().asFile, "reports/bom.json"))
+
+        val patchBTA = File(temporaryDir, "patches/custom.jarmod.bta.json")
+        patchBTA.createNewFile()
+        patchBTA.writeText(File(instanceTemplatesDir, "patches/custom.jarmod.bta.json").readText().replace("\$version", versionUnderscored))
+
+        File(layout.buildDirectory.get().asFile, "libs/bta-client.jar").copyTo(File(temporaryDir, "jarmods/bta.jar"))
+
+        val inputDirectory = temporaryDir
+        val outputZipFile = File(layout.buildDirectory.get().asFile, "libs/instance.zip")
+        outputZipFile.delete()
+        ZipOutputStream(BufferedOutputStream(FileOutputStream(outputZipFile))).use { zos ->
+            inputDirectory.walkTopDown().forEach { file ->
+                val zipFileName = file.absolutePath.replace("\\", "/").removePrefix(inputDirectory.absolutePath.replace("\\", "/")).removePrefix("/")
+                if (!zipFileName.isEmpty()) {
+                    val entry = ZipEntry( "$zipFileName${(if (file.isDirectory) "/" else "" )}")
+                    zos.putNextEntry(entry)
+                    if (file.isFile) {
+                        file.inputStream().use { fis -> fis.copyTo(zos) }
+                    }
+                }
+            }
+        }
+    }
+}
+
+fun generateMcPatchesFile(inputDir: File, outputDir: File, sbom: File) {
+    val sbom = JsonParser.parseString(sbom.readText()).asJsonObject
+
+    val mavenUrls = arrayOf("https://libraries.minecraft.net/", "https://repo.maven.apache.org/maven2/", "https://jitpack.io/")
+
+    val libraryComponents: MutableList<JsonElement> = mutableListOf();
+    val compArr = sbom.getAsJsonArray("components")
+
+    var errorStr = ""
+    var failed = false
+    label@ for (component in compArr) {
+        val group = component.asJsonObject.get("group").asString
+        val name = component.asJsonObject.get("name").asString
+        val version = component.asJsonObject.get("version").asString
+
+        for (p in projects) {
+            if (name == project(p).name) continue@label
+        }
+
+        if (group.contains("lwjgl") || version.equals("unspecified") || name.equals("client")) {
+            continue
+        }
+
+        var succeeded = false
+        var localErrorString = "Failed to resolve dependency \"$group:$name:$version\"\n"
+        for (mavenUrl in mavenUrls) {
+            val url = URL("${mavenUrl}${group.replace(".", "/")}/${name}/${version}/${name}-${version}.jar")
+            try {
+                url.openStream().close()
+
+                val compObj = JsonObject()
+                compObj.addProperty("name", "$group:$name:$version")
+                compObj.addProperty("url", mavenUrl)
+
+                libraryComponents.add(compObj)
+                succeeded = true;
+                break
+            } catch (e: Exception) {
+                localErrorString += "\tFailed to locate at \"$url\"\n"
+            }
+        }
+        if (!succeeded) {
+            failed = true
+            errorStr += localErrorString
+        }
+
+    }
+    if (failed) {
+        throw GradleException("Could not resolve all required dependencies!\n $errorStr")
+    }
+
+    val gson = GsonBuilder().setPrettyPrinting().create()
+    val json = JsonParser.parseString(File(inputDir, "patches/net.minecraft.json").readText()).asJsonObject
+
+    if (libraryComponents.isNotEmpty()) {
+        val librariesArr = JsonArray(libraryComponents.size)
+        libraryComponents.forEach { element -> librariesArr.add(element) }
+        json.add("libraries", librariesArr)
+    }
+
+    val patchMC = File(outputDir, "patches/net.minecraft.json")
+    patchMC.createNewFile()
+    patchMC.writeText(gson.toJson(json))
+}
+
+tasks.cyclonedxBom {
+    setIncludeConfigs(listOf("runtimeClasspath"))
+    setSkipConfigs(listOf("compileClasspath", "testCompileClasspath"))
+
+    val skipProjects = mutableSetOf(rootProject.name)
+    skipProjects.addAll(projects)
+    skipProjects.add(":util:datagen")
+    setSkipProjects(skipProjects)
+
+    setProjectType("application")
+    setSchemaVersion("1.6")
+    setDestination(project.file("build/reports"))
+    setOutputName("bom")
+    setOutputFormat("json")
+    setIncludeBomSerialNumber(false)
+    setIncludeLicenseText(true)
+    setIncludeMetadataResolution(true)
+    setComponentVersion("2.0.0")
+    setComponentName("my-component")
+}
+
 tasks.withType(JavaCompile::class.java) {
     options.isIncremental = false
     options.encoding = "UTF-8"
diff --git a/game/client/instance/icon.png b/game/client/instance/icon.png
new file mode 100644
index 000000000..a61379189
Binary files /dev/null and b/game/client/instance/icon.png differ
diff --git a/game/client/instance/instance.cfg b/game/client/instance/instance.cfg
new file mode 100644
index 000000000..1d39f319c
--- /dev/null
+++ b/game/client/instance/instance.cfg
@@ -0,0 +1,5 @@
+InstanceType=OneSix
+iconKey=v$version
+name=Better than Adventure! (Managed)
+JvmArgs=-XX:+UseG1GC -Dsun.rmi.dgc.server.gcInterval=2147483646 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M
+notes=
diff --git a/game/client/instance/mmc-pack.json b/game/client/instance/mmc-pack.json
new file mode 100644
index 000000000..cff664b8a
--- /dev/null
+++ b/game/client/instance/mmc-pack.json
@@ -0,0 +1,31 @@
+{
+    "components": [
+        {
+            "cachedName": "LWJGL 3",
+            "cachedVersion": "3.3.3",
+            "cachedVolatile": true,
+            "dependencyOnly": true,
+            "uid": "org.lwjgl",
+            "version": "3.3.3"
+        },
+        {
+            "cachedName": "Minecraft",
+            "cachedRequires": [
+                {
+                    "suggests": "3.3.3",
+                    "uid": "org.lwjgl"
+                }
+            ],
+            "cachedVersion": "b1.7.3",
+            "important": true,
+            "uid": "net.minecraft",
+            "version": "b1.7.3"
+        },
+        {
+            "cachedName": "Better than Adventure!",
+            "cachedVersion": "$version",
+            "uid": "custom.jarmod.bta"
+        }
+    ],
+    "formatVersion": 1
+}
diff --git a/game/client/instance/patches/custom.jarmod.bta.json b/game/client/instance/patches/custom.jarmod.bta.json
new file mode 100644
index 000000000..00249d8db
--- /dev/null
+++ b/game/client/instance/patches/custom.jarmod.bta.json
@@ -0,0 +1,14 @@
+{
+    "formatVersion": 1,
+    "jarMods": [
+        {
+            "MMC-displayname": "Better than Adventure!",
+            "MMC-filename": "bta.jar",
+            "MMC-hint": "local",
+            "name": "custom.jarmods:bta:1"
+        }
+    ],
+    "name": "Better than Adventure!",
+    "uid": "custom.jarmod.bta",
+    "version": "$version"
+}
diff --git a/game/client/instance/patches/net.minecraft.json b/game/client/instance/patches/net.minecraft.json
new file mode 100644
index 000000000..884924ace
--- /dev/null
+++ b/game/client/instance/patches/net.minecraft.json
@@ -0,0 +1,37 @@
+{
+    "+traits": [
+        "texturepacks",
+        "noapplet",
+        "legacyLaunch",
+        "FirstThreadOnMacOS"
+    ],
+    "formatVersion": 1,
+    "compatibleJavaMajors": [
+        8, 17
+    ],
+    "compatibleJavaName": "java-runtime-gamma",
+    "mainJar": {
+        "downloads": {
+            "artifact": {
+                "sha1": "43db9b498cb67058d2e12d394e6507722e71bb45",
+                "size": 1465375,
+                "url": "https://launcher.mojang.com/v1/objects/43db9b498cb67058d2e12d394e6507722e71bb45/client.jar"
+            }
+        },
+        "name": "com.mojang:minecraft:b1.7.3:client"
+    },
+    "minecraftArguments": "--username ${auth_player_name} --session ${auth_session} --gameDir ${game_directory} --uuid ${auth_uuid}",
+    "name": "Minecraft",
+    "releaseTime": "2011-07-08T00:00:00+02:00",
+    "type": "old_beta",
+    "uid": "net.minecraft",
+    "version": "b1.7.3",
+    "requires": [
+        {
+            "suggests": "3.3.3",
+            "uid": "org.lwjgl"
+        }
+    ],
+    "libraries": [
+    ]
+}
diff --git a/game/client/instance/patches/org.lwjgl.json b/game/client/instance/patches/org.lwjgl.json
new file mode 100644
index 000000000..51e2f611a
--- /dev/null
+++ b/game/client/instance/patches/org.lwjgl.json
@@ -0,0 +1,1339 @@
+{
+    "formatVersion": 1,
+    "libraries": [
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "149070a5480900347071b7074779531f25a6e3dc",
+                    "size": 1245129,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "b0a8c9baa9d1f54ac61e1ab9640c7659e7fa700c",
+                    "size": 1040981,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "1e9b635b5c16b515527b905749be59223e338c4d",
+                    "size": 1142682,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "82028265a0a2ff33523ca75137ada7dc176e5210",
+                    "size": 886068,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "15a8c1de7f51d07a92eae7ce1222557073a0c0c3",
+                    "size": 877480,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "81091b006dbb43fab04c8c638e9ac87c51b4096d",
+                    "size": 1035586,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a0db6c84a8becc8ca05f9dbfa985edc348a824c7",
+                    "size": 450896,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-freetype/3.3.3/lwjgl-freetype-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a03684c5e4b1b1dbbe0d29dbbdc27b985b6840f2",
+                    "size": 118478,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "ee8cc78d0a4a5b3b4600fade6d927c9fc320c858",
+                    "size": 138288,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a1bf400f6bc64e6195596cb1430dafda46090751",
+                    "size": 140884,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "f27018dc74f6289574502b46cce55d52817554e2",
+                    "size": 141970,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "32334f3fd5270a59bad9939a93115acb6de36dcf",
+                    "size": 157123,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "e449e28b4891fc423c54c85fbc5bb0b9efece67a",
+                    "size": 166368,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "efa1eb78c5ccd840e9f329717109b5e892d72f8e",
+                    "size": 135546,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-glfw/3.3.3/lwjgl-glfw-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "4f86728bf449b1dd61251c4e0ac01df1389cb51e",
+                    "size": 206779,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "e9412c3ff8cb3a3bad1d3f52909ad74d8a5bdad1",
+                    "size": 141418,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "2906637657a57579847238c9c72d2c4bde7083f8",
+                    "size": 153131,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "ba1f3fed0ee4be0217eaa41c5bbfb4b9b1383c33",
+                    "size": 154415,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "f6063b6e0f23be483c5c88d84ce51b39dc69126c",
+                    "size": 148612,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "426222fc027602a5f21b9c0fe79cde6a4c7a011f",
+                    "size": 180344,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "b543467b7ff3c6920539a88ee602d34098628be5",
+                    "size": 43896,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-jemalloc/3.3.3/lwjgl-jemalloc-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "1713758e3660ba66e1e954396fd18126038b33c0",
+                    "size": 114627,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "226246e75f6bd8d4e1895bdce8638ef87808d114",
+                    "size": 48620,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "33a6efa288390490ce6eb6c3df47ac21ecf648cf",
+                    "size": 60543,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "e9aca8c5479b520a2a7f0d542a118140e812c5e8",
+                    "size": 133378,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "9e670718e050aeaeea0c2d5b907cffb142f2e58f",
+                    "size": 139653,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a5ed18a2b82fc91b81f40d717cb1f64c9dcb0540",
+                    "size": 165442,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "3037360cc4595079bea240af250b6d1a527e0905",
+                    "size": 573224,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "0c78b078de2fb52f45aa55d04db889a560f3544f",
+                    "size": 471012,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "8df8338bfa77f2ebabef4e58964bd04d24805cbf",
+                    "size": 519824,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "8e0615235116b9e4160dfe87bec90f5f6378bf72",
+                    "size": 630410,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "87b8d5050e3adb46bb58fe1cb2669a4a48fce10d",
+                    "size": 638424,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "cf83862ae95d98496b26915024c7e666d8ab1c8f",
+                    "size": 698720,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "daada81ceb5fc0c291fbfdd4433cb8d9423577f2",
+                    "size": 110586,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-openal/3.3.3/lwjgl-openal-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "62c70a4b00ca5391882b0f4b787c1588d24f1c86",
+                    "size": 80463,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "d213ddef27637b1af87961ffa94d6b27036becc8",
+                    "size": 42487,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "1bd45997551ae8a28469f3a2b678f4b7289e12c0",
+                    "size": 41484,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "65e956d3735a1abdc82eff4baec1b61174697d4b",
+                    "size": 83095,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "0d32d833dcaa2f355a886eaf21f0408b5f03241d",
+                    "size": 88612,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "e6c1eec8be8a71951b830a4d69efc01c6531900c",
+                    "size": 101535,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "02f6b0147078396a58979125a4c947664e98293a",
+                    "size": 929192,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-opengl/3.3.3/lwjgl-opengl-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "fd1271ccd9d85eff2fa31f3fd543e02ccfaf5041",
+                    "size": 231820,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "51c6955571fbcdb7bb538c6aa589b953b584c6af",
+                    "size": 183628,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "472792c98fb2c1557c060cb9da5fca6a9773621f",
+                    "size": 216456,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a584ab44de569708871f0a79561f4d8c37487f2c",
+                    "size": 219511,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "b5c874687b9aac1a936501d4ed2c49567fd1b575",
+                    "size": 227800,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "1d9facdf6541de114b0f963be33505b7679c78cb",
+                    "size": 261297,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "25dd6161988d7e65f71d5065c99902402ee32746",
+                    "size": 120283,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-stb/3.3.3/lwjgl-stb-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "d8d58daa0c3e5fd906fee96f5fddbcbc07cc308b",
+                    "size": 44192,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-linux.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-linux:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "406feedb977372085a61eb0fee358183f4f4c67a",
+                    "size": 42498,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-macos-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-macos-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "6598081e346a03038a8be68eb2de614a1c2eac68",
+                    "size": 45865,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-macos.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-macos:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "osx"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a88c494f3006eb91a7433b12a3a55a9a6c20788b",
+                    "size": 110867,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-windows-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-windows-arm64:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                },
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "c336c84ee88cccb495c6ffa112395509e7378e8a",
+                    "size": 111797,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-windows-x86.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-windows-x86:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "a6697981b0449a5087c1d546fc08b4f73e8f98c9",
+                    "size": 130253,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3-natives-windows.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-windows:3.3.3",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "windows"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "82d755ca94b102e9ca77283b9e2dc46d1b15fbe5",
+                    "size": 13400,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl-tinyfd/3.3.3/lwjgl-tinyfd-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "29589b5f87ed335a6c7e7ee6a5775f81f97ecb84",
+                    "size": 785029,
+                    "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.3.3/lwjgl-3.3.3.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl:3.3.3"
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "498965aac06c4a0d42df1fbef6bacd05bde7f974",
+                    "size": 1093516,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-freetype/lwjgl-freetype-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "7dd3b1f751571adaf2c4dc882bc675a5d1e796e6",
+                    "size": 942636,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-freetype/lwjgl-freetype-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-freetype-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "492a0f11f85b85899a6568f07511160c1b87cd38",
+                    "size": 122159,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-glfw/lwjgl-glfw-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "d9af485c32545b37dd5359b163161d42d7534dcf",
+                    "size": 112560,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-glfw/lwjgl-glfw-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-glfw-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "eff8b86798191192fe2cba2dc2776109f30c239d",
+                    "size": 209315,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-jemalloc/lwjgl-jemalloc-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "109b6931880d02d4e65ced38928a16e41d19873e",
+                    "size": 178324,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-jemalloc/lwjgl-jemalloc-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-jemalloc-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "ad8f302118a65bb8d615f8a2a680db58fb8f835e",
+                    "size": 592963,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-openal/lwjgl-openal-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "e1702aa09d20359d6cf5cb2999fa7685a785eca7",
+                    "size": 505618,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-openal/lwjgl-openal-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-openal-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "2096f6b94b2d68745d858fbfe53aacf5f0c8074c",
+                    "size": 58625,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-opengl/lwjgl-opengl-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "dbba17fc5ac0985d14a57c11f9537617d67b9952",
+                    "size": 59263,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-opengl/lwjgl-opengl-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-opengl-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "ddc177afc2be1ee8d93684b11363b80589a13fe1",
+                    "size": 207418,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-stb/lwjgl-stb-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "1ae28ff044699ff29b0e980ffabd73fba8a664b3",
+                    "size": 154931,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-stb/lwjgl-stb-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-stb-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "2823a8c955c758d0954d282888075019ef99cec7",
+                    "size": 43864,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-tinyfd/lwjgl-tinyfd-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "c2a0a05c82c4b9f69ded0b6ad5f417addea78ce2",
+                    "size": 49495,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl-tinyfd/lwjgl-tinyfd-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-tinyfd-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "f35d8b6ffe1ac1e3a5eb1d4e33de80f044ad5fd8",
+                    "size": 91294,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl/lwjgl-natives-linux-arm64.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-linux-arm64:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm64"
+                    }
+                }
+            ]
+        },
+        {
+            "downloads": {
+                "artifact": {
+                    "sha1": "2075c51a80f0ef0f22ba616ba54007ac2b0debd4",
+                    "size": 89565,
+                    "url": "https://build.lwjgl.org/release/3.3.3/bin/lwjgl/lwjgl-natives-linux-arm32.jar"
+                }
+            },
+            "name": "org.lwjgl:lwjgl-natives-linux-arm32:3.3.3-lwjgl.1",
+            "rules": [
+                {
+                    "action": "allow",
+                    "os": {
+                        "name": "linux-arm32"
+                    }
+                }
+            ]
+        }
+    ],
+    "name": "LWJGL 3",
+    "releaseTime": "2024-04-22T13:42:34+00:00",
+    "type": "release",
+    "uid": "org.lwjgl",
+    "version": "3.3.3",
+    "volatile": true
+}
diff --git a/game/client/instance/pathmap.json b/game/client/instance/pathmap.json
new file mode 100644
index 000000000..79a04692f
--- /dev/null
+++ b/game/client/instance/pathmap.json
@@ -0,0 +1,9 @@
+{
+	"jarmods/bta.jar": "/jarmods/bta.jar",
+	"patches/net.minecraft.json": "/patches/net.minecraft.json",
+	"patches/org.lwjgl.json": "/patches/org.lwjgl.json",
+	"patches/custom.jarmod.bta.json": "/patches/custom.jarmod.bta.json",
+	"v$version.png": "../../icons/v$version.png",
+	"instance.cfg": "/instance.cfg",
+	"mmc-pack.json": "/mmc-pack.json"
+}
diff --git a/game/client/src/main/java/net/minecraft/client/Minecraft.java b/game/client/src/main/java/net/minecraft/client/Minecraft.java
index 6241e6b16..51ef4cb84 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -215,7 +215,7 @@ public class Minecraft
     public static final boolean isMultiplayerDisabled = false;
     public static boolean doPartialTick = true;
     public static EnumGPUVendor GPU_VENDOR = EnumGPUVendor.UNKNOWN;
-    private static Minecraft INSTANCE;
+    private static @NotNull Minecraft INSTANCE;
     public PlayerController playerController;
     public boolean hasCrashed;
     public UnexpectedThrowable lastCrash;
@@ -251,7 +251,7 @@ public class Minecraft
     public boolean skipRenderWorld;
     public @Nullable HitResult objectMouseOver;
     public final @NotNull GameSettings gameSettings;
-    public SoundEngine sndManager;
+    public @NotNull SoundEngine sndManager;
     public final @NotNull SubtitleTracker subtitleTracker = new SubtitleTracker();
     public final @NotNull TexturePackList texturePackList;
     private final @NotNull File mcDataDir;
@@ -274,7 +274,7 @@ public class Minecraft
     protected long flyPressedTime = 0;
     public static final int HOTBAR_SWAP_ANIMATION_LENGTH_TICKS = 3;
     public int hotbarSwapAnimationProgress = 0;
-    public ScaledResolution resolution;
+    public @NotNull ScaledResolution resolution;
     public boolean fullbright = false;
     public Renderer renderer;
     public @Nullable ControllerInput controllerInput;
@@ -285,7 +285,7 @@ public class Minecraft
     public Thread rpcThread = null;
     public PostProcessingManager ppm = new PostProcessingManager(this);
     private long lastFocusTime;
-    public GameWindow gameWindow;
+    public @NotNull GameWindow gameWindow;
     public ClientSkinVariantList skinVariantList = new ClientSkinVariantList(this);
     public MainMenuBackground mainMenuBackground = new MainMenuBackground(this);
     public @Nullable Integer overrideWidth = null;
@@ -913,7 +913,7 @@ public class Minecraft
         return saveFormat;
     }
 
-    public void displayScreen(Screen screen)
+    public void displayScreen(@Nullable Screen screen)
     {
         if(currentScreen == null && screen != null)
         {
@@ -2918,7 +2918,7 @@ public class Minecraft
         return GLFW.glfwGetClipboardString(this.gameWindow.getHandle());
     }
 
-    public static Minecraft getMinecraft() {
+    public static @NotNull Minecraft getMinecraft() {
         return INSTANCE;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ButtonElement.java b/game/client/src/main/java/net/minecraft/client/gui/ButtonElement.java
index 2ec3b471e..4d18331c1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ButtonElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ButtonElement.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.window.CursorShape;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.opengl.GL11;
 
@@ -53,7 +54,7 @@ public class ButtonElement extends Gui implements GuiElement
         disabledTexture = TextureRegistry.getTexture("minecraft:gui/widgets/button/button_disabled");
     }
 
-    public ButtonElement setTextures(@Nullable String defaultTexture, @Nullable String hoveredTexture, @Nullable String disabledTexture) {
+    public @NotNull ButtonElement setTextures(@Nullable String defaultTexture, @Nullable String hoveredTexture, @Nullable String disabledTexture) {
         if (defaultTexture != null) {
             this.defaultTexture = TextureRegistry.getTexture(defaultTexture);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ExceptionPopupElement.java b/game/client/src/main/java/net/minecraft/client/gui/ExceptionPopupElement.java
index d2cb66ab9..7131acf16 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ExceptionPopupElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ExceptionPopupElement.java
@@ -6,6 +6,7 @@ import net.minecraft.client.gui.popup.PopupBuilder;
 import net.minecraft.client.gui.popup.PopupCloseListener;
 import net.minecraft.core.Global;
 import net.minecraft.core.net.command.TextFormatting;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.Sys;
 import org.lwjgl.opengl.GL11;
 
@@ -147,7 +148,7 @@ public class ExceptionPopupElement {
         }
 
         @Override
-        public void onClosed(int statusCode, Map<String, ?> results) {
+        public void onClosed(int statusCode, @NotNull Map<String, ?> results) {
             switch (statusCode){
                 case 0:
                     mc.hasCrashed = false;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
index 1a4f46e74..219689e0c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ItemElement.java
@@ -16,17 +16,14 @@ import net.minecraft.client.gui.guidebook.SlotGuidebook;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL12;
 
-public class ItemElement extends Gui
-{
+public class ItemElement extends Gui {
     Minecraft mc;
 
-    public ItemElement(Minecraft mc)
-    {
+    public ItemElement(final Minecraft mc) {
         this.mc = mc;
     }
 
-    public void render(ItemStack itemStack, int x, int y, boolean isSelected, Slot slot)
-    {
+    public void render(final ItemStack itemStack, final int x, final int y, final boolean isSelected, final Slot slot) {
         boolean hasDrawnSlotBackground = false;
         boolean discovered = true;
 
@@ -36,15 +33,13 @@ public class ItemElement extends Gui
         GL11.glEnable(GL12.GL_RESCALE_NORMAL);
 
         // Draw slot background
-        if (slot != null)
-        {
-            discovered = slot.getIsDiscovered(mc.thePlayer);
+        if (slot != null) {
+            discovered = slot.getIsDiscovered(this.mc.thePlayer);
             if (slot.getItemIcon() != null) {
                 final IconCoordinate iconIndex = TextureRegistry.getTexture(slot.getItemIcon());
-                if (itemStack == null)
-                {
+                if (itemStack == null) {
                     GL11.glDisable(GL11.GL_LIGHTING);
-                    drawTexturedIcon(x, y, 16, 16, iconIndex);
+                    this.drawTexturedIcon(x, y, 16, 16, iconIndex);
                     GL11.glEnable(GL11.GL_LIGHTING);
                     hasDrawnSlotBackground = true;
                 }
@@ -54,49 +49,47 @@ public class ItemElement extends Gui
                 GL11.glColor4f(1, 1, 1, 1);
                 GL11.glDisable(GL11.GL_LIGHTING);
                 final IconCoordinate iconCoordinate = TextureRegistry.getTexture("minecraft:gui/slot_locked");
-                drawGuiIcon(x - 1, y - 1, 18, 18, iconCoordinate);
+                this.drawGuiIcon(x - 1, y - 1, 18, 18, iconCoordinate);
                 GL11.glEnable(GL11.GL_LIGHTING);
             }
         }
 
         // Draw item
-        if (!hasDrawnSlotBackground)
-        {
+        if (!hasDrawnSlotBackground) {
             GL11.glEnable(GL11.GL_DEPTH_TEST);
-            if (itemStack != null){
-                ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
+            if (itemStack != null) {
+                final ItemModel itemModel = ItemModelDispatcher.getInstance().getDispatch(itemStack.getItem());
                 itemModel.renderGui(Tessellator.instance, null, itemStack, x, y, discovered ? 1.0f : 0.0f, 1.0f, 1f);
-                if(slot instanceof SlotGuidebook){
-                    if(((SlotGuidebook) slot).recipe instanceof RecipeEntryTrommel && ((SlotGuidebook) slot).item != null && ((SlotGuidebook) slot).isOutput){
-                        WeightedRandomBag<WeightedRandomLootObject> loot = ((RecipeEntryTrommel)((SlotGuidebook) slot).recipe).getOutput();
+                if (slot instanceof SlotGuidebook) {
+                    if (((SlotGuidebook) slot).recipe instanceof RecipeEntryTrommel && ((SlotGuidebook) slot).item != null && ((SlotGuidebook) slot).isOutput) {
+                        final WeightedRandomBag<WeightedRandomLootObject> loot = ((RecipeEntryTrommel) ((SlotGuidebook) slot).recipe).getOutput();
                         int index = slot.index;
-                        if(((SlotGuidebook) slot).recipeAmount > 8){
+                        if (((SlotGuidebook) slot).recipeAmount > 8) {
                             index = slot.index + (9 * ((SlotGuidebook) slot).recipeIndex);
                         }
-                        WeightedRandomLootObject lootObject = loot.getEntries().get(index);
-                        String s;
-                        if(lootObject.isRandomYield()){
-                            s = String.format("%d-%d",lootObject.getMinYield(),lootObject.getMaxYield());
+                        final WeightedRandomLootObject lootObject = loot.getEntries().get(index);
+                        final String s;
+                        if (lootObject.isRandomYield()) {
+                            s = String.format("%d-%d", lootObject.getMinYield(), lootObject.getMaxYield());
                         } else {
                             s = String.valueOf(lootObject.getFixedYield());
                         }
-                        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, discovered ? s : "?", 1.0f);
+                        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, this.mc.font, this.mc.textureManager, itemStack, x, y, discovered ? s : "?", 1.0f);
                     } else {
-                        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, discovered ? null : "?", 1.0f);
+                        itemModel.renderItemOverlayIntoGUI(Tessellator.instance, this.mc.font, this.mc.textureManager, itemStack, x, y, discovered ? null : "?", 1.0f);
                     }
                 } else {
-                    itemModel.renderItemOverlayIntoGUI(Tessellator.instance, mc.font, mc.textureManager, itemStack, x, y, discovered ? null : "?", 1.0f);
+                    itemModel.renderItemOverlayIntoGUI(Tessellator.instance, this.mc.font, this.mc.textureManager, itemStack, x, y, discovered ? null : "?", 1.0f);
                 }
             }
             GL11.glDisable(GL11.GL_DEPTH_TEST);
         }
 
         // Draw selection overlay
-        if (isSelected)
-        {
+        if (isSelected) {
             GL11.glDisable(GL11.GL_LIGHTING);
             GL11.glDisable(GL11.GL_DEPTH_TEST);
-            drawRect(x, y, x + 16, y + 16, 0x80FFFFFF);
+            this.drawRect(x, y, x + 16, y + 16, 0x80FFFFFF);
             GL11.glEnable(GL11.GL_LIGHTING);
             GL11.glEnable(GL11.GL_DEPTH_TEST);
         }
@@ -108,13 +101,11 @@ public class ItemElement extends Gui
         GL11.glDisable(GL11.GL_DEPTH_TEST);
     }
 
-    public void render(ItemStack itemStack, int x, int y, boolean isSelected)
-    {
-        render(itemStack, x, y, isSelected, null);
+    public void render(final ItemStack itemStack, final int x, final int y, final boolean isSelected) {
+        this.render(itemStack, x, y, isSelected, null);
     }
 
-    public void render(ItemStack itemStack, int x, int y)
-    {
-        render(itemStack, x, y, false);
+    public void render(final ItemStack itemStack, final int x, final int y) {
+        this.render(itemStack, x, y, false);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/Screen.java b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
index a107205bf..02e3e754b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/Screen.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/Screen.java
@@ -24,15 +24,14 @@ public abstract class Screen extends Gui {
     public final @NotNull Minecraft mc = Minecraft.getMinecraft();
     public int width;
     public int height;
-    public List<ButtonElement> buttons;
+    public @NotNull List<@NotNull ButtonElement> buttons;
     public boolean passEvents;
-    public FontRenderer fontRenderer;
-    protected ButtonElement clickedButton;
-    protected final Screen parentScreen;
-    private CursorShape desiredCursor = CursorShape.ARROW;
+    public @NotNull FontRenderer fontRenderer = this.mc.font;
+    protected @Nullable ButtonElement clickedButton;
+    protected final @Nullable Screen parentScreen;
+    private @NotNull CursorShape desiredCursor = CursorShape.ARROW;
 
-    public Screen(@Nullable final Screen parent) {
-        super();
+    public Screen(final @Nullable Screen parent) {
         this.buttons = new ArrayList<>();
         this.passEvents = false;
         this.clickedButton = null;
@@ -43,51 +42,50 @@ public abstract class Screen extends Gui {
         this(null);
     }
 
-    public Screen getParentScreen() {
-        return parentScreen;
+    public @Nullable Screen getParentScreen() {
+        return this.parentScreen;
     }
 
-    public final CursorShape getDesiredCursor() {
+    public final @NotNull CursorShape getDesiredCursor() {
         return this.desiredCursor;
     }
 
-    public final void setDesiredCursor(CursorShape desiredCursor) {
+    public final void setDesiredCursor(final @NotNull CursorShape desiredCursor) {
         this.desiredCursor = desiredCursor;
     }
 
-    public <E extends ButtonElement> E add(E button) {
-        buttons.add(button);
+    public <E extends ButtonElement> @NotNull E add(final @NotNull E button) {
+        this.buttons.add(button);
         return button;
     }
 
-    public void render(int mx, int my, float partialTick) {
-        for (int i = 0; i < buttons.size(); i++) {
-            ButtonElement button = buttons.get(i);
-            button.drawButton(mc, mx, my);
+    public void render(final int mx, final int my, final float partialTick) {
+        for (final ButtonElement button : this.buttons) {
+            button.drawButton(this.mc, mx, my);
         }
     }
 
-    public void keyPressed(char eventCharacter, int eventKey, int mx, int my) {
+    public void keyPressed(final char eventCharacter, final int eventKey, final int mx, final int my) {
         if (eventKey == Keyboard.KEY_BACK) {
-            mc.displayScreen(parentScreen);
+            this.mc.displayScreen(this.parentScreen);
         }
         if (eventKey == Keyboard.KEY_ESCAPE) {
-            mc.displayScreen(null);
+            this.mc.displayScreen(null);
         }
     }
 
-    public void mouseClicked(int mx, int my, int buttonNum) {
+    public void mouseClicked(final int mx, final int my, final int buttonNum) {
         if (buttonNum == 0) {
-            for (ButtonElement button : buttons) {
-                if (button.mouseClicked(mc, mx, my)) {
-                    clickedButton = button;
+            for (final @NotNull ButtonElement button : this.buttons) {
+                if (button.mouseClicked(this.mc, mx, my)) {
+                    this.clickedButton = button;
                     if (button.playSound) {
-                        mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+                        this.mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
                     }
                     if (button.listener != null) {
                         button.listener.listen(button);
                     } else {
-                        buttonClicked(button);
+                        this.buttonClicked(button);
                     }
                     return;
                 }
@@ -95,64 +93,64 @@ public abstract class Screen extends Gui {
         }
     }
 
-    public void mouseReleased(int mx, int my, int buttonNum) {
-        if (clickedButton != null && buttonNum == 0) {
-            buttonReleased(clickedButton);
-            clickedButton.mouseReleased(mx, my);
-            clickedButton = null;
+    public void mouseReleased(final int mx, final int my, final int buttonNum) {
+        if (this.clickedButton != null && buttonNum == 0) {
+            this.buttonReleased(this.clickedButton);
+            this.clickedButton.mouseReleased(mx, my);
+            this.clickedButton = null;
         }
     }
 
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(final @NotNull ButtonElement button) {
     }
 
-    protected void buttonReleased(ButtonElement button) {
+    protected void buttonReleased(final @NotNull ButtonElement button) {
     }
 
-    public void opened(int width, int height) {
-        fontRenderer = mc.font;
+    public void opened(final int width, final int height) {
+        this.updateFont();
         this.width = width;
         this.height = height;
-        buttons.clear();
-        init();
+        this.buttons.clear();
+        this.init();
     }
 
     public void init() {
     }
 
     public void updateEvents() {
-        int mouseX = (Mouse.getEventX() * width) / mc.resolution.getWidthScreenCoords();
-        int mouseY = height - (Mouse.getEventY() * height) / mc.resolution.getHeightScreenCoords() - 1;
+        final int mouseX = (Mouse.getEventX() * this.width) / this.mc.resolution.getWidthScreenCoords();
+        final int mouseY = this.height - (Mouse.getEventY() * this.height) / this.mc.resolution.getHeightScreenCoords() - 1;
 
         while (Mouse.next()) {
-            if (mc.inputType == InputType.CONTROLLER) break;
+            if (this.mc.inputType == InputType.CONTROLLER) break;
 
             if (Mouse.getEventButtonState()) {
-                mouseClicked(mouseX, mouseY, Mouse.getEventButton());
+                this.mouseClicked(mouseX, mouseY, Mouse.getEventButton());
             } else {
-                mouseReleased(mouseX, mouseY, Mouse.getEventButton());
+                this.mouseReleased(mouseX, mouseY, Mouse.getEventButton());
             }
         }
         while (Keyboard.next()) {
-            if (Keyboard.getEventKeyState() && mc.gameSettings.showFrameTimes.value && DebugRender.keyPressed(Keyboard.getEventKey())) {
+            if (Keyboard.getEventKeyState() && this.mc.gameSettings.showFrameTimes.isTrue() && DebugRender.keyPressed(Keyboard.getEventKey())) {
                 continue;
             }
-            int eventKey = Keyboard.getEventKey();
-            char eventChar = Keyboard.getEventCharacter();
+            final int eventKey = Keyboard.getEventKey();
+            final char eventChar = Keyboard.getEventCharacter();
             if (eventKey == 0 && Character.isDefined(eventChar)) {
-                keyPressed(eventChar, eventKey, mouseX, mouseY);
+                this.keyPressed(eventChar, eventKey, mouseX, mouseY);
                 return;
             }
             if (Keyboard.getEventKeyState()) {
                 if (eventKey == Keyboard.KEY_F11) {
-                    mc.gameWindow.toggleFullscreen();
+                    this.mc.gameWindow.toggleFullscreen();
                     return;
                 }
-                if (!(this instanceof ScreenConsole) && eventKey == mc.gameSettings.keyShowConsole.getKeyCode() && mc.gameSettings.developerMode.value && !Keyboard.areRepeatEventsEnabled()) {
-                    mc.displayScreen(new ScreenConsole(this));
+                if (!(this instanceof ScreenConsole) && eventKey == this.mc.gameSettings.keyShowConsole.getKeyCode() && this.mc.gameSettings.developerMode.isTrue() && !Keyboard.areRepeatEventsEnabled()) {
+                    this.mc.displayScreen(new ScreenConsole(this));
                     return;
                 }
-                keyPressed(eventChar, eventKey, mouseX, mouseY);
+                this.keyPressed(eventChar, eventKey, mouseX, mouseY);
             }
         }
     }
@@ -164,54 +162,54 @@ public abstract class Screen extends Gui {
     }
 
     public void renderBackground() {
-        if (mc.currentWorld != null) {
-            int color = mc.gameSettings.guiBackgroundColor.value.getARGB();
-            drawGradientRect(0, 0, width, height, color, color);
+        if (this.mc.currentWorld != null) {
+            final int color = this.mc.gameSettings.guiBackgroundColor.value.getARGB();
+            this.drawGradientRect(0, 0, this.width, this.height, color, color);
         } else {
-            renderTexturedBackground();
+            this.renderTexturedBackground();
         }
     }
 
     public void renderTexturedBackground() {
         GL11.glDisable(GL11.GL_LIGHTING);
         GL11.glDisable(GL11.GL_FOG);
-        Tessellator tessellator = Tessellator.instance;
-        mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
+        final Tessellator tessellator = Tessellator.instance;
+        this.mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-        float f = 32F;
+        final float scale = 32F;
         tessellator.startDrawingQuads();
         tessellator.setColorOpaque_I(0x404040);
-        tessellator.addVertexWithUV(0.0D, height, 0.0D, 0.0D, (float) height / f);
-        tessellator.addVertexWithUV(width, height, 0.0D, (float) width / f, (float) height / f);
-        tessellator.addVertexWithUV(width, 0.0D, 0.0D, (float) width / f, 0);
+        tessellator.addVertexWithUV(0.0D, this.height, 0.0D, 0.0D, (float) this.height / scale);
+        tessellator.addVertexWithUV(this.width, this.height, 0.0D, (float) this.width / scale, (float) this.height / scale);
+        tessellator.addVertexWithUV(this.width, 0.0D, 0.0D, (float) this.width / scale, 0);
         tessellator.addVertexWithUV(0.0D, 0.0D, 0.0D, 0.0D, 0);
         tessellator.draw();
     }
 
     public void drawControllerCursor() {
-        if (mc.controllerInput.hideCursor) return;
+        if (this.mc.controllerInput == null || this.mc.controllerInput.hideCursor) return;
         glDisable(GL_DEPTH_TEST);
         glEnable(GL_BLEND);
         glColor3d(1.0, 1.0, 1.0);
-        drawGuiTexture(mc.textureManager, (int) (mc.controllerInput.cursorX - 8), (int) (mc.controllerInput.cursorY - 8), 16, 16, "/assets/minecraft/textures/gui/controller/cursor.png");
+        this.drawGuiTexture(this.mc.textureManager, (int) (this.mc.controllerInput.cursorX - 8), (int) (this.mc.controllerInput.cursorY - 8), 16, 16, "/assets/minecraft/textures/gui/controller/cursor.png");
         glDisable(GL_BLEND);
     }
 
-    public void controllerInput(ControllerInput controller) {
-        guiSpecificControllerInput(controller);
-        playControllerButtonSound(controller);
+    public void controllerInput(final @NotNull ControllerInput controller) {
+        this.guiSpecificControllerInput(controller);
+        this.playControllerButtonSound(controller);
     }
 
-    public void playControllerButtonSound(ControllerInput controller) {
+    public void playControllerButtonSound(final @NotNull ControllerInput controller) {
         if (controller.buttonA.pressedThisFrame() || controller.buttonX.pressedThisFrame() || controller.buttonY.pressedThisFrame()) {
-            mc.sndManager.playSound("ui.ui_click", SoundCategory.GUI_SOUNDS, 1.0f, 1.0f);
+            this.mc.sndManager.playSound("ui.ui_click", SoundCategory.GUI_SOUNDS, 1.0f, 1.0f);
         }
         if (controller.buttonB.pressedThisFrame()) {
-            mc.sndManager.playSound("ui.ui_back", SoundCategory.GUI_SOUNDS, 1.0f, 1.0f);
+            this.mc.sndManager.playSound("ui.ui_back", SoundCategory.GUI_SOUNDS, 1.0f, 1.0f);
         }
     }
 
-    public void guiSpecificControllerInput(ControllerInput controller) {
+    public void guiSpecificControllerInput(final @NotNull ControllerInput controller) {
         this.mouseReleased((int)controller.cursorX, (int)controller.cursorY, -1);
         if(controller.buttonB.pressedThisFrame()) {
             this.keyPressed((char)0, Keyboard.KEY_BACK, -1, -1);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenAddServer.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenAddServer.java
index c69c474ec..133002802 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenAddServer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenAddServer.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui;
 import net.minecraft.core.net.ServerData;
 import net.minecraft.core.net.SavedServerList;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 
 public class ScreenAddServer extends Screen
@@ -57,7 +58,7 @@ public class ScreenAddServer extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectFailed.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectFailed.java
index afa150337..8c9f15c57 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectFailed.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectFailed.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 public class ScreenConnectFailed extends Screen
 {
@@ -44,7 +45,7 @@ public class ScreenConnectFailed extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(button.id == 0)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectToIp.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectToIp.java
index 8bb58bb8b..71e9c0207 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectToIp.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnectToIp.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui;
 
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.ServerAddress;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 
 public class ScreenConnectToIp extends Screen
@@ -40,7 +41,7 @@ public class ScreenConnectToIp extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnecting.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnecting.java
index bd490ad0c..9bc0a89d1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConnecting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConnecting.java
@@ -5,6 +5,7 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.net.handler.PacketHandlerClient;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.packet.PacketPreLogin;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 import java.net.ConnectException;
@@ -86,7 +87,7 @@ public class ScreenConnecting extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(button.id == 0)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenControllerSetup.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenControllerSetup.java
index 11cc12ce4..80f4c1155 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenControllerSetup.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenControllerSetup.java
@@ -6,6 +6,7 @@ import net.minecraft.client.input.controller.Button;
 import net.minecraft.client.input.controller.ControllerInput;
 import net.minecraft.client.input.controller.ControllerType;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Arrays;
 
@@ -126,7 +127,7 @@ public class ScreenControllerSetup extends Screen {
     public void keyPressed(char eventCharacter, int eventKey, int mx, int my) { }
 
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull ButtonElement button) {
         super.buttonClicked(button);
 
         if (button.id == 0) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
index 08a853f00..4a1196839 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenCreateWorld.java
@@ -10,6 +10,7 @@ import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.settings.WorldConfiguration;
 import net.minecraft.core.world.type.WorldTypeGroups;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 
 import java.util.List;
@@ -68,7 +69,7 @@ public class ScreenCreateWorld extends Screen {
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull ButtonElement button) {
         if (!button.enabled) {
             return;
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenDownloadTerrain.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenDownloadTerrain.java
index d776d2bb8..ccf7e2506 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenDownloadTerrain.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenDownloadTerrain.java
@@ -3,6 +3,7 @@ package net.minecraft.client.gui;
 import net.minecraft.client.net.handler.PacketHandlerClient;
 import net.minecraft.core.net.packet.PacketKeepAlive;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 public class ScreenDownloadTerrain extends Screen
 {
@@ -39,7 +40,7 @@ public class ScreenDownloadTerrain extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenGameOver.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenGameOver.java
index 46fb3619e..0e10fbf8e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenGameOver.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenGameOver.java
@@ -4,6 +4,7 @@ import net.minecraft.client.entity.player.PlayerLocalMultiplayer;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.packet.PacketKeepAlive;
 import net.minecraft.core.player.gamemode.Gamemode;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.core.net.command.TextFormatting;
@@ -44,7 +45,7 @@ public class ScreenGameOver extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(button.id == 1)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenHudDesigner.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenHudDesigner.java
index 52a06c8ca..3517e491a 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenHudDesigner.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenHudDesigner.java
@@ -10,6 +10,7 @@ import net.minecraft.client.gui.hud.component.layout.LayoutSnap;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 import java.util.ArrayList;
@@ -50,7 +51,7 @@ public class ScreenHudDesigner
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull ButtonElement button) {
         super.buttonClicked(button);
         if (button.id == 0) {
             mc.displayScreen(getParentScreen());
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java
index 2a4d2613e..286eb873d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java
@@ -9,6 +9,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.net.packet.PacketSetItemName;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -49,7 +50,7 @@ public class ScreenLabelEditor extends Screen implements ITextField
     }
 
     @Override
-    protected void buttonClicked(final ButtonElement button)
+    protected void buttonClicked(final @NotNull ButtonElement button)
     {
         if (!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
index c67571377..a72a61e4b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMainMenu.java
@@ -200,7 +200,7 @@ public class ScreenMainMenu extends Screen
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
         switch (button.id) {
             case 0:
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenPause.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenPause.java
index 9e4266709..38bcd3fd5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenPause.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenPause.java
@@ -14,6 +14,7 @@ import net.minecraft.core.achievement.stat.StatList;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.client.input.InputType;
+import org.jetbrains.annotations.NotNull;
 
 public class ScreenPause extends Screen
 {
@@ -54,7 +55,7 @@ public class ScreenPause extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         switch (button.id) {
             case 0:
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenPhotoMode.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenPhotoMode.java
index 119fc21d8..3157f9b9c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenPhotoMode.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenPhotoMode.java
@@ -7,6 +7,7 @@ import net.minecraft.core.Global;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.season.Seasons;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -216,7 +217,7 @@ public class ScreenPhotoMode extends Screen
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
         if (button == buttonRotateLeft)
         {
@@ -511,7 +512,7 @@ public class ScreenPhotoMode extends Screen
     }
 
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller) {
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller) {
         super.guiSpecificControllerInput(controller);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectServer.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectServer.java
index 9e7f6cc05..5b1464721 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectServer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectServer.java
@@ -11,6 +11,7 @@ import net.minecraft.core.net.SavedServerList;
 import net.minecraft.core.net.ServerAddress;
 import net.minecraft.core.net.ServerData;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.crypto.Cipher;
@@ -89,7 +90,7 @@ public class ScreenSelectServer extends Screen {
 	}
 
 	@Override
-	protected void buttonClicked(ButtonElement button) {
+	protected void buttonClicked(@NotNull ButtonElement button) {
 		if(!button.enabled) {
 			return;
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
index 6395aaa4a..e4821053f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSelectWorld.java
@@ -182,7 +182,7 @@ public class ScreenSelectWorld extends Screen
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled) {
             return;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
index 3bccdbba2..8e15eaf18 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java
@@ -81,7 +81,7 @@ public class ScreenSignEditor extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
@@ -209,7 +209,7 @@ public class ScreenSignEditor extends Screen
     }
 
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller) {
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller) {
         super.guiSpecificControllerInput(controller);
         if (controller.digitalPad.up.pressedThisFrame()) {
             editLine = editLine - 1 & 3;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSleepSP.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSleepSP.java
index ee6ca6110..b1f7467cf 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSleepSP.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSleepSP.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.gui;
 
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 
 public class ScreenSleepSP extends Screen {
@@ -19,7 +20,7 @@ public class ScreenSleepSP extends Screen {
 	}
 	
 	@Override
-	protected void buttonClicked(ButtonElement button) {
+	protected void buttonClicked(@NotNull ButtonElement button) {
 		if(button.id == 1) {
 			wakeUp();
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSoundTest.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSoundTest.java
index cf5488740..8153e701b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSoundTest.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSoundTest.java
@@ -12,6 +12,7 @@ import net.minecraft.client.util.helper.FileOpener;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -137,11 +138,11 @@ public class ScreenSoundTest extends Screen {
                 }});
     }
 
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
     }
 
-    protected void buttonReleased(ButtonElement button)
+    protected void buttonReleased(@NotNull ButtonElement button)
     {
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
index 51c21e870..aa5eab8f5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenStats.java
@@ -10,6 +10,7 @@ import net.minecraft.core.item.Item;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL12;
@@ -71,7 +72,7 @@ public class ScreenStats extends Screen {
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenTextureViewer.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenTextureViewer.java
index eb120d727..3d30cc8d5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenTextureViewer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenTextureViewer.java
@@ -9,6 +9,7 @@ import net.minecraft.client.render.texture.Texture;
 import net.minecraft.client.util.helper.FileOpener;
 import net.minecraft.client.util.helper.Textures;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -99,11 +100,11 @@ public class ScreenTextureViewer extends Screen {
         );
     }
 
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
     }
 
-    protected void buttonReleased(ButtonElement button)
+    protected void buttonReleased(@NotNull ButtonElement button)
     {
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
index ccfce48e5..d9df13fac 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/achievements/ScreenAchievements.java
@@ -184,7 +184,7 @@ public class ScreenAchievements extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button) {
+	protected void buttonClicked(@NotNull ButtonElement button) {
         if(button.id == 1) {
             mc.displayScreen(parent);
             //mc.setIngameFocus();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenSleepMP.java b/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenSleepMP.java
index e42b43a56..18a7451d6 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenSleepMP.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenSleepMP.java
@@ -7,6 +7,7 @@ import net.minecraft.core.net.packet.PacketUpdatePlayerState;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.net.ChatEmotes;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 
 public class ScreenSleepMP extends ScreenChat
@@ -49,7 +50,7 @@ public class ScreenSleepMP extends ScreenChat
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(button.id == 1)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
index 1591c2e7c..f0056c498 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
@@ -30,6 +30,7 @@ import net.minecraft.core.player.inventory.menu.*;
 import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.core.player.inventory.slot.SlotResult;
 import net.minecraft.core.player.inventory.slot.SlotCreative;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -505,7 +506,7 @@ public abstract class ScreenContainerAbstract extends Screen
 		int[] args = new int[] { slotId, target };
 		mc.playerController.handleInventoryMouseClick(inventorySlots.containerId, action, args, mc.thePlayer);
 	}
-	public void controllerInput(ControllerInput controller){
+	public void controllerInput(@NotNull ControllerInput controller){
 		Slot slot = controller.getSlotAtCursor(this);
 
 //		if(joyLeft.stoppedMoving()) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenCrafting.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenCrafting.java
index a8cd96504..1d2cfe77c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenCrafting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenCrafting.java
@@ -5,6 +5,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.player.inventory.container.ContainerInventory;
 import net.minecraft.core.player.inventory.menu.MenuCrafting;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 public class ScreenCrafting extends ScreenContainerAbstract
@@ -38,7 +39,7 @@ public class ScreenCrafting extends ScreenContainerAbstract
         drawTexturedModalRect(j, k, 0, 0, xSize, ySize);
     }
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller){
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller){
         super.guiSpecificControllerInput(controller);
         controller.inventoryHandler.handleCrafting(this);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
index 910e3dd0b..8ad9ec4ba 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFlagEditor.java
@@ -7,6 +7,7 @@ import net.minecraft.client.gui.DrawableSurfaceElement;
 import net.minecraft.client.gui.TexturedButtonElement;
 import net.minecraft.core.block.entity.TileEntityFlag;
 import net.minecraft.core.entity.player.Player;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -222,7 +223,7 @@ public class ScreenFlagEditor
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
         super.buttonClicked(button);
         if (button.id >= 0 && button.id < 7)
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
index e7c32aa16..da552c1f2 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
@@ -6,6 +6,7 @@ import net.minecraft.core.block.entity.TileEntityFurnaceBlast;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.player.inventory.menu.MenuFurnace;
 import net.minecraft.core.player.inventory.container.ContainerInventory;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 public class ScreenFurnace extends ScreenContainerAbstract
@@ -42,7 +43,7 @@ public class ScreenFurnace extends ScreenContainerAbstract
         }
     }
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller){
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller){
         super.guiSpecificControllerInput(controller);
         controller.inventoryHandler.handleFurnace(this);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java
index 68a4b9e58..0b856472b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java
@@ -43,7 +43,7 @@ public class ScreenFurnaceBlast
     }
 
     @Override
-    public void guiSpecificControllerInput(final ControllerInput controller) {
+    public void guiSpecificControllerInput(final @NotNull ControllerInput controller) {
         super.guiSpecificControllerInput(controller);
         controller.inventoryHandler.handleFurnaceBlast(this);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventory.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventory.java
index 7a1aba857..cacf3487d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventory.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventory.java
@@ -25,6 +25,7 @@ import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.EntityRenderDispatcher;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.core.util.helper.Color;
@@ -300,7 +301,7 @@ public class ScreenInventory extends ScreenContainerAbstract
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if (button == armorButton) {
         	mc.gameSettings.armorProtectionOverlay.toggle();
@@ -308,7 +309,7 @@ public class ScreenInventory extends ScreenContainerAbstract
     }
 
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller){
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller){
         super.guiSpecificControllerInput(controller);
         controller.inventoryHandler.handleInventory(this);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java
index 72742b02f..85daf0176 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenInventoryCreative.java
@@ -12,6 +12,7 @@ import net.minecraft.core.player.inventory.menu.MenuInventoryCreative;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.EntityRenderDispatcher;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -97,7 +98,7 @@ public class ScreenInventoryCreative extends ScreenInventory implements ITextCha
 	}
 	
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
 		super.buttonClicked(button);
     	if (!button.enabled)
@@ -232,7 +233,7 @@ public class ScreenInventoryCreative extends ScreenInventory implements ITextCha
 		updatePageSwitcher();
 	}
 	@Override
-	public void guiSpecificControllerInput(ControllerInput controller){
+	public void guiSpecificControllerInput(@NotNull ControllerInput controller){
 		if(controller.buttonLeftShoulder.pressedThisFrame()) {
 			this.scroll(1);
 		}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenBadJavaArch.java b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenBadJavaArch.java
index 1ca47a171..85322c11c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenBadJavaArch.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenBadJavaArch.java
@@ -7,6 +7,7 @@ import net.minecraft.client.gui.ScreenMainMenu;
 import net.minecraft.client.util.helper.UrlHelper;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 
 public class ScreenBadJavaArch extends Screen
 {
@@ -25,7 +26,7 @@ public class ScreenBadJavaArch extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenConflictWarning.java b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenConflictWarning.java
index 9dc92c1b4..cda86fd8e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenConflictWarning.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenConflictWarning.java
@@ -4,6 +4,7 @@ import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.gui.ScreenMainMenu;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 public class ScreenConflictWarning extends Screen
 {
@@ -20,7 +21,7 @@ public class ScreenConflictWarning extends Screen
     }
 
     @Override
-	protected void buttonClicked(ButtonElement button)
+	protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingJCE.java b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingJCE.java
index 20d0cf8a2..970abab8c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingJCE.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingJCE.java
@@ -49,7 +49,7 @@ public class ScreenMissingJCE extends Screen {
     }
 
     @Override
-    protected void buttonClicked(final ButtonElement button)
+    protected void buttonClicked(final @NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
@@ -73,7 +73,7 @@ public class ScreenMissingJCE extends Screen {
     }
 
     @Override
-    protected void buttonReleased(ButtonElement button) {
+    protected void buttonReleased(@NotNull ButtonElement button) {
         if (button.id == 1) {
             this.continueHeld = false;
             this.clickStart = 0;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingMinecraft.java b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingMinecraft.java
index 6ecf5780e..cd0b82495 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingMinecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/error/ScreenMissingMinecraft.java
@@ -8,6 +8,7 @@ import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.util.helper.UrlHelper;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 import org.slf4j.Logger;
 
@@ -42,7 +43,7 @@ public class ScreenMissingMinecraft extends Screen {
         super.render(mx, my, partialTick);
     }
     @Override
-    protected void buttonClicked(ButtonElement button)
+    protected void buttonClicked(@NotNull ButtonElement button)
     {
         if(!button.enabled)
         {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
index eaf4fcf2f..b617c7e2c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/ScreenGuidebook.java
@@ -19,6 +19,7 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -318,7 +319,7 @@ public class ScreenGuidebook
         mc.sndManager.playSound("random.page", SoundCategory.GUI_SOUNDS, 0.8f, 0.9f + (r.nextFloat() - r.nextFloat()) * 0.1f);
     }
 
-    public void guiSpecificControllerInput(ControllerInput controller){
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller){
         super.guiSpecificControllerInput(controller);
         if (controller.digitalPad.left.pressedThisFrame() || (controller.digitalPad.left.isPressed() && controller.digitalPad.left.getHoldTime() % 4 == 0)){
             guidebookPageManager.offsetPage(-2);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java b/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java
index 7001f0262..982ac2a5b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java
@@ -247,7 +247,7 @@ public class ScreenKeyboard extends Screen implements ITextField {
     }
 
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller) {
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller) {
         int keyboardWidth = keyboardLayout.getWidth();
         int keyboardHeight = keyboardLayout.getHeight();
 
@@ -356,7 +356,7 @@ public class ScreenKeyboard extends Screen implements ITextField {
     }
 
     @Override
-    public void playControllerButtonSound(ControllerInput controller) {
+    public void playControllerButtonSound(@NotNull ControllerInput controller) {
         if (controller.buttonStart.pressedThisFrame()) {
             mc.sndManager.playSound("ui.ui_click", SoundCategory.GUI_SOUNDS, 1.0f, 1.0f);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
index dea91a594..fc583f7aa 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/ScreenModelViewer.java
@@ -462,7 +462,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
 //        mc.theWorld.getLevelData().setWorldTime(mc.theWorld.getWorldTime() + 1);
     }
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull ButtonElement button) {
         // Overrides the regular GuiPhotomode's method
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
index aac134037..6f64a7b56 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/ScreenOptions.java
@@ -157,7 +157,7 @@ public class ScreenOptions
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull ButtonElement button) {
         super.buttonClicked(button);
 
         if (button.id == 0)
@@ -581,7 +581,7 @@ public class ScreenOptions
     }
 
     @Override
-    public void guiSpecificControllerInput(ControllerInput controller) {
+    public void guiSpecificControllerInput(@NotNull ControllerInput controller) {
         if(controller.buttonStart.pressedThisFrame()) {
             this.keyPressed((char)0, Keyboard.KEY_ESCAPE, -1, -1);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
index 64ef2a28c..dc0a9653e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/DifficultyOptionComponent.java
@@ -11,6 +11,8 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.Objects;
+
 public class DifficultyOptionComponent extends ButtonComponent {
 
     protected final OptionEnum<Difficulty> option;
@@ -36,7 +38,7 @@ public class DifficultyOptionComponent extends ButtonComponent {
         onChanged();
         this.option.onUpdate();
         if (mc.currentWorld != null && this.lockButton.mouseClicked(mc, this.slider.xPosition + relativeMouseX, this.slider.yPosition + relativeMouseY)) {
-            mc.displayScreen(new PopupBuilder(mc.currentScreen, 160)
+            mc.displayScreen(new PopupBuilder(Objects.requireNonNull(mc.currentScreen), 160)
                     .withLabel("gui.options.difficultylock.warning.1")
                     .withLabel("gui.options.difficultylock.warning.2")
                     .withLabel("gui.options.difficultylock.warning.3", 0xFF0000)
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index 6e8836a25..5ada75d6f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
@@ -337,6 +337,7 @@ public abstract class OptionsPages
             )
             .withComponent(new OptionsCategory("gui.options.page.debug.category.settings")
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.developerMode))
+                .withComponent(new BooleanOptionComponent(mc.gameSettings.viewSupportMode))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.alphaMenu))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.lockCamera))
                 .withComponent(new BooleanOptionComponent(mc.gameSettings.showDebugScreen))
diff --git a/game/client/src/main/java/net/minecraft/client/gui/paged/Page.java b/game/client/src/main/java/net/minecraft/client/gui/paged/Page.java
index e71ae27e4..a22b93b82 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/paged/Page.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/paged/Page.java
@@ -2,56 +2,51 @@ package net.minecraft.client.gui.paged;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class Page {
     private static final int COMPONENT_SPACING = 4;
-    private final String translationKey;
-    private final List<PageComponent> components = new ArrayList<>();
-    private final ItemStack icon;
+    private final @NotNull String translationKey;
+    private final @NotNull List<@NotNull PageComponent> components = new ArrayList<>();
+    private final @NotNull ItemStack icon;
 
-    public Page(String translationKey, ItemStack icon) {
+    public Page(final @NotNull String translationKey, final @NotNull ItemStack icon) {
         this.translationKey = translationKey;
         this.icon = icon;
     }
 
-    public Page withComponent(PageComponent component)
-    {
-        components.add(component);
+    public @NotNull Page withComponent(final @NotNull PageComponent component) {
+        this.components.add(component);
         return this;
     }
 
-    public String getTranslationKey()
-    {
-        return translationKey;
+    public @NotNull String getTranslationKey() {
+        return this.translationKey;
     }
 
-    public List<PageComponent> getComponents()
-    {
-        return components;
+    public @NotNull List<@NotNull PageComponent> getComponents() {
+        return this.components;
     }
 
-    public void initComponents(Minecraft mc) {
-        for (PageComponent component : components) {
+    public void initComponents(final @NotNull Minecraft mc) {
+        for (final @NotNull PageComponent component : this.components) {
             component.init(mc);
         }
     }
 
-    public int getHeight()
-    {
+    public int getHeight() {
         int height = 0;
-        for (PageComponent component : components)
-        {
+        for (final @NotNull PageComponent component : this.components) {
             height += component.getHeight() + COMPONENT_SPACING;
         }
         height -= COMPONENT_SPACING;
         return height;
     }
 
-    public ItemStack getIcon()
-    {
-        return icon;
+    public @NotNull  ItemStack getIcon() {
+        return this.icon;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/paged/PageRegistry.java b/game/client/src/main/java/net/minecraft/client/gui/paged/PageRegistry.java
index 5ce0ad5c7..22a9c4094 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/paged/PageRegistry.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/paged/PageRegistry.java
@@ -1,25 +1,27 @@
 package net.minecraft.client.gui.paged;
 
+import org.jetbrains.annotations.NotNull;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 public class PageRegistry {
-    private final List<Page> pages = new ArrayList<>();
+    private final @NotNull List<@NotNull Page> pages = new ArrayList<>();
 
-    public Page register(Page page) {
-        if (!pages.contains(page)) {
-            pages.add(page);
+    public @NotNull Page register(final @NotNull Page page) {
+        if (!this.pages.contains(page)) {
+            this.pages.add(page);
         }
 
         return page;
     }
 
-    public int getPageIndex(Page page) {
-        return pages.indexOf(page);
+    public int getPageIndex(final @NotNull Page page) {
+        return this.pages.indexOf(page);
     }
 
-    public List<Page> getPages() {
-        return Collections.unmodifiableList(pages);
+    public @NotNull List<@NotNull Page> getPages() {
+        return Collections.unmodifiableList(this.pages);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java b/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
index c1ebf91fb..cb1cac4ae 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/paged/ScreenPaged.java
@@ -7,6 +7,8 @@ import net.minecraft.client.render.Scissor;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -21,25 +23,31 @@ public class ScreenPaged
     private static final int PADDING = 8;
     private static final int PAGE_BUTTON_HEIGHT = 20;
 
-    private final String titleTranslationKey;
-    private final String[] buttonTranslationKeys;
+    private final @NotNull String titleTranslationKey;
+    private final @NotNull String @NotNull [] buttonTranslationKeys;
 
     private float rightScrollAmount = 0.0f;
     private float leftScrollAmount = 0.0f;
     private int top, bottom, rightScrollRegionHeight, leftScrollRegionHeight, pageWidth, leftWidth;
 
-    private Float oldRightScrollAmount;
-    private Float oldLeftScrollAmount;
-    private Integer clickX, clickY;
-    private Page selectedPage;
-    private PageComponent clickedComponent;
+    private @Nullable Float oldRightScrollAmount = null;
+    private @Nullable Float oldLeftScrollAmount = null;
+    private @Nullable Integer clickX;
+    private @Nullable Integer clickY;
+    private @NotNull Page selectedPage;
+    private @Nullable PageComponent clickedComponent;
     private int clickedComponentY;
-    private ItemElement renderItem = null;
+    private @Nullable ItemElement renderItem = null;
 
-    private final PageRegistry pageRegistry;
+    private final @NotNull PageRegistry pageRegistry;
 
-    public ScreenPaged(Screen parent, PageRegistry pageRegistry, Page selectedPage, String titleTranslationKey, String[] buttonTranslationKeys)
-    {
+    public ScreenPaged(
+        final @Nullable Screen parent,
+        final @NotNull PageRegistry pageRegistry,
+        final @Nullable Page selectedPage,
+        final @NotNull String titleTranslationKey,
+        final @NotNull String @NotNull [] buttonTranslationKeys
+    ) {
         super(parent);
         this.pageRegistry = pageRegistry;
         if (selectedPage == null) {
@@ -52,183 +60,184 @@ public class ScreenPaged
     }
 
     @Override
-    public void init()
-    {
+    public void init() {
         super.init();
 
-        int buttonWidth = 200 - (buttonTranslationKeys.length - 1) * 40;
-        int totalButtonsWidth = buttonTranslationKeys.length * (buttonWidth + 4) - 4;
-        for (int i = 0; i < buttonTranslationKeys.length; i++) {
-            String buttonTranslationKey = buttonTranslationKeys[i];
-            buttons.add(new ButtonElement(i, width / 2 - totalButtonsWidth / 2 + ((buttonWidth + 4) * i), height - (BUTTON_SPACING + 20), buttonWidth, 20, I18n.getInstance().translateKey(buttonTranslationKey)));
+        final int buttonWidth = 200 - (this.buttonTranslationKeys.length - 1) * 40;
+        final int totalButtonsWidth = this.buttonTranslationKeys.length * (buttonWidth + 4) - 4;
+        for (int i = 0; i < this.buttonTranslationKeys.length; i++) {
+            final @NotNull String buttonTranslationKey = this.buttonTranslationKeys[i];
+            this.buttons.add(
+                new ButtonElement(
+                    i,
+                    this.width / 2 - totalButtonsWidth / 2 + ((buttonWidth + 4) * i),
+                    this.height - (BUTTON_SPACING + 20),
+                    buttonWidth,
+                    20,
+                    I18n.getInstance().translateKey(buttonTranslationKey)
+                )
+            );
         }
 
-        top = TOP_SPACING;
-        bottom = height - (BUTTON_SPACING + 20 + BUTTON_SPACING);
+        this.top = TOP_SPACING;
+        this.bottom = this.height - (BUTTON_SPACING + 20 + BUTTON_SPACING);
 
-        rightScrollRegionHeight = bottom - top;
-        leftScrollRegionHeight = bottom - top;
+        this.rightScrollRegionHeight = this.bottom - this.top;
+        this.leftScrollRegionHeight = this.bottom - this.top;
 
-        this.renderItem = new ItemElement(mc);
+        this.renderItem = new ItemElement(this.mc);
 
-        this.selectedPage.initComponents(mc);
+        this.selectedPage.initComponents(this.mc);
     }
 
     @Override
-    public void keyPressed(char eventCharacter, int eventKey, int mx, int my) {
-        if (eventKey == Keyboard.KEY_ESCAPE)
-        {
-            mc.displayScreen(getParentScreen());
-        }
-        else
-        {
-            for (PageComponent component : selectedPage.getComponents())
-            {
+    public void keyPressed(final char eventCharacter, final int eventKey, final int mx, final int my) {
+        if (eventKey == Keyboard.KEY_ESCAPE) {
+            this.mc.displayScreen(this.getParentScreen());
+        } else {
+            for (final @NotNull PageComponent component : this.selectedPage.getComponents()) {
                 component.onKeyPress(eventKey, eventCharacter);
             }
         }
     }
 
-    private void drawPageItems(int x, int y, int width, int mouseX, int mouseY)
-    {
+    private void drawPageItems(final int x, final int y, final int width, final int mouseX, final int mouseY) {
         int y2 = y;
-        for (PageComponent component : selectedPage.getComponents())
-        {
+        for (final @NotNull PageComponent component : this.selectedPage.getComponents()) {
             component.render(x, y2, width, mouseX - x, mouseY - y2);
             y2 += component.getHeight();
         }
     }
 
-    private void drawPagesListItems(int x, int y, int width, int mouseX, int mouseY) {
+    private void drawPagesListItems(final int x, final int y, final int width, final int mouseX, final int mouseY) {
         int y2 = y;
-        for(Page page : pageRegistry.getPages()) {
-            String translated = I18n.getInstance().translateKey(page.getTranslationKey());
+        for (final @NotNull Page page : this.pageRegistry.getPages()) {
+            final String translated = I18n.getInstance().translateKey(page.getTranslationKey());
             int textColor = 0xFF7F7F7F;
-            if (page == selectedPage) {
+            if (page == this.selectedPage) {
                 textColor = 0xFFFFFFFF;
             }
             if (mouseX >= x && mouseX < x + width && mouseY >= y2 && mouseY < y2 + PAGE_BUTTON_HEIGHT) {
                 textColor = 0xFFFFFFA0;
             }
-            renderItem.render(page.getIcon(), x, y2 + (PAGE_BUTTON_HEIGHT / 2) - 9);
-            drawStringShadow(this.fontRenderer, translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
+            assert this.renderItem != null;
+            this.renderItem.render(page.getIcon(), x, y2 + (PAGE_BUTTON_HEIGHT / 2) - 9);
+            this.drawStringShadow(this.fontRenderer, translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
             y2 += PAGE_BUTTON_HEIGHT;
         }
     }
 
     @Override
     public void tick() {
-        for (PageComponent component : selectedPage.getComponents())
-        {
+        for (final PageComponent component : this.selectedPage.getComponents()) {
             component.tick();
         }
     }
 
     @Override
-    protected void buttonClicked(ButtonElement button) {
+    protected void buttonClicked(@NotNull final ButtonElement button) {
         super.buttonClicked(button);
 
-        if (button.id == 0)
-        {
-            mc.displayScreen(getParentScreen());
-            mc.texturePackList.refreshIfReady(); // Sets the texturepacks on menu close
+        if (button.id == 0) {
+            this.mc.displayScreen(this.getParentScreen());
+            this.mc.texturePackList.refreshIfReady(); // Sets the texturepacks on menu close
         }
     }
 
-    private void scrollRightPanel(float amount) {
-        if(amount == 0.0f) return;
+    private void scrollRightPanel(final float amount) {
+        if (amount == 0.0f) return;
 
-        rightScrollAmount += amount;
-        onScrollRightPanel();
+        this.rightScrollAmount += amount;
+        this.onScrollRightPanel();
     }
 
     private void onScrollRightPanel() {
-        int totalRightPanelHeight = getTotalRightPanelHeight();
-        if (rightScrollAmount < 0 || rightScrollRegionHeight > totalRightPanelHeight) rightScrollAmount = 0;
-        else if (rightScrollAmount > totalRightPanelHeight - rightScrollRegionHeight) rightScrollAmount = totalRightPanelHeight - rightScrollRegionHeight;
+        final int totalRightPanelHeight = this.getTotalRightPanelHeight();
+        if (this.rightScrollAmount < 0 || this.rightScrollRegionHeight > totalRightPanelHeight) this.rightScrollAmount = 0;
+        else if (this.rightScrollAmount > totalRightPanelHeight - this.rightScrollRegionHeight)
+            this.rightScrollAmount = totalRightPanelHeight - this.rightScrollRegionHeight;
     }
 
-    private void scrollLeftPanel(float amount) {
-        if(amount == 0.0f) return;
+    private void scrollLeftPanel(final float amount) {
+        if (amount == 0.0f) return;
 
-        leftScrollAmount += amount;
-        onScrollLeftPanel();
+        this.leftScrollAmount += amount;
+        this.onScrollLeftPanel();
     }
 
     private void onScrollLeftPanel() {
-        int totalLeftPanelHeight = getTotalLeftPanelHeight();
-        if (leftScrollAmount < 0 || leftScrollRegionHeight > totalLeftPanelHeight) leftScrollAmount = 0;
-        else if (leftScrollAmount > totalLeftPanelHeight - leftScrollRegionHeight) leftScrollAmount = totalLeftPanelHeight - leftScrollRegionHeight;
+        final int totalLeftPanelHeight = this.getTotalLeftPanelHeight();
+        if (this.leftScrollAmount < 0 || this.leftScrollRegionHeight > totalLeftPanelHeight) {
+            this.leftScrollAmount = 0;
+        } else if (this.leftScrollAmount > totalLeftPanelHeight - this.leftScrollRegionHeight) {
+            this.leftScrollAmount = totalLeftPanelHeight - this.leftScrollRegionHeight;
+        }
     }
 
-    private int getTotalRightPanelHeight()
-    {
+    private int getTotalRightPanelHeight() {
         int totalPageHeight = 0;
-        for (PageComponent component : selectedPage.getComponents())
-        {
+        for (final PageComponent component : this.selectedPage.getComponents()) {
             totalPageHeight += component.getHeight();
         }
         return totalPageHeight;
     }
 
     private int getTotalLeftPanelHeight() {
-        return PAGE_BUTTON_HEIGHT * pageRegistry.getPages().size();
+        return PAGE_BUTTON_HEIGHT * this.pageRegistry.getPages().size();
     }
 
     @Override
-    public void render(int mx, int my, float renderPartialTicks)
-    {
-        if (mx > leftWidth + SEPARATOR_WIDTH + PADDING && mx < width) {
+    public void render(final int mx, final int my, final float renderPartialTicks) {
+        if (mx > this.leftWidth + SEPARATOR_WIDTH + PADDING && mx < this.width) {
             if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
-                scrollRightPanel(Mouse.getDWheel() / -0.01f);
+                this.scrollRightPanel(Mouse.getDWheel() / -0.01f);
             } else {
-                scrollRightPanel(Mouse.getDWheel() / -0.05f);
+                this.scrollRightPanel(Mouse.getDWheel() / -0.05f);
             }
-            onScrollRightPanel();
-        } else if (mx >= 0 && mx <= leftWidth) {
+            this.onScrollRightPanel();
+        } else if (mx >= 0 && mx <= this.leftWidth) {
             if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
-                scrollLeftPanel(Mouse.getDWheel() / -0.01f);
+                this.scrollLeftPanel(Mouse.getDWheel() / -0.01f);
             } else {
-                scrollLeftPanel(Mouse.getDWheel() / -0.05f);
+                this.scrollLeftPanel(Mouse.getDWheel() / -0.05f);
             }
-            onScrollLeftPanel();
+            this.onScrollLeftPanel();
         }
 
-        leftWidth = (int)(width * 0.25f);
-        pageWidth = width - (leftWidth + SEPARATOR_WIDTH + (PADDING * 2));
-        I18n i18n = I18n.getInstance();
+        this.leftWidth = (int) (this.width * 0.25f);
+        this.pageWidth = this.width - (this.leftWidth + SEPARATOR_WIDTH + (PADDING * 2));
+        final @NotNull I18n i18n = I18n.getInstance();
 
-        renderBackground();
-        overlayBackground(0, width, 0, top);
-        overlayBackground(0, width, bottom, height);
+        this.renderBackground();
+        this.overlayBackground(0, this.width, 0, this.top);
+        this.overlayBackground(0, this.width, this.bottom, this.height);
 
-        Scissor.enable(0, top, width, bottom - top);
-        if (my >= top && my <= bottom) {
-            drawPageItems(leftWidth + SEPARATOR_WIDTH + PADDING, top - (int) rightScrollAmount, pageWidth - 8, mx, my);
+        Scissor.enable(0, this.top, this.width, this.bottom - this.top);
+        if (my >= this.top && my <= this.bottom) {
+            this.drawPageItems(this.leftWidth + SEPARATOR_WIDTH + PADDING, this.top - (int) this.rightScrollAmount, this.pageWidth - 8, mx, my);
         } else {
-            drawPageItems(leftWidth + SEPARATOR_WIDTH + PADDING, top - (int) rightScrollAmount, pageWidth - 8, -1, -1);
+            this.drawPageItems(this.leftWidth + SEPARATOR_WIDTH + PADDING, this.top - (int) this.rightScrollAmount, this.pageWidth - 8, -1, -1);
         }
         Scissor.disable();
 
-        Scissor.enable(0, top, leftWidth, bottom - top);
-        int pagesListHeight = getTotalLeftPanelHeight();
-        int pagesListY = top - (int) leftScrollAmount;
-        if (pagesListHeight < bottom - top) {
-            pagesListY = top + (bottom - top - pagesListHeight) / 2;
+        Scissor.enable(0, this.top, this.leftWidth, this.bottom - this.top);
+        final int pagesListHeight = this.getTotalLeftPanelHeight();
+        int pagesListY = this.top - (int) this.leftScrollAmount;
+        if (pagesListHeight < this.bottom - this.top) {
+            pagesListY = this.top + (this.bottom - this.top - pagesListHeight) / 2;
         }
-        if (my >= top && my <= bottom) {
-            drawPagesListItems(PADDING - 4, pagesListY, leftWidth - PADDING, mx, my);
+        if (my >= this.top && my <= this.bottom) {
+            this.drawPagesListItems(PADDING - 4, pagesListY, this.leftWidth - PADDING, mx, my);
         } else {
-            drawPagesListItems(PADDING - 4, pagesListY, leftWidth - PADDING, -1, -1);
+            this.drawPagesListItems(PADDING - 4, pagesListY, this.leftWidth - PADDING, -1, -1);
         }
         Scissor.disable();
 
         // Draw shadows
-        if (mc.currentWorld == null)
-        {
-            Tessellator tessellator = Tessellator.instance;
+        if (this.mc.currentWorld == null) {
+            final Tessellator tessellator = Tessellator.instance;
             GL11.glDisable(GL_DEPTH_TEST);
-            int shadowSize = 4;
+            final int shadowSize = 4;
             GL11.glEnable(GL_BLEND);
             GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
             GL11.glDisable(GL_ALPHA_TEST);
@@ -237,20 +246,20 @@ public class ScreenPaged
 
             tessellator.startDrawingQuads();
             tessellator.setColorRGBA_I(0, 0);
-            tessellator.addVertexWithUV(0, top + shadowSize, 0.0D, 0.0D, 1.0D);
-            tessellator.addVertexWithUV(width, top + shadowSize, 0.0D, 1.0D, 1.0D);
+            tessellator.addVertexWithUV(0, this.top + shadowSize, 0.0D, 0.0D, 1.0D);
+            tessellator.addVertexWithUV(this.width, this.top + shadowSize, 0.0D, 1.0D, 1.0D);
             tessellator.setColorRGBA_I(0, 255);
-            tessellator.addVertexWithUV(width, top, 0.0D, 1.0D, 0.0D);
-            tessellator.addVertexWithUV(0, top, 0.0D, 0.0D, 0.0D);
+            tessellator.addVertexWithUV(this.width, this.top, 0.0D, 1.0D, 0.0D);
+            tessellator.addVertexWithUV(0, this.top, 0.0D, 0.0D, 0.0D);
             tessellator.draw();
 
             tessellator.startDrawingQuads();
             tessellator.setColorRGBA_I(0, 255);
-            tessellator.addVertexWithUV(0, bottom, 0.0D, 0.0D, 1.0D);
-            tessellator.addVertexWithUV(width, bottom, 0.0D, 1.0D, 1.0D);
+            tessellator.addVertexWithUV(0, this.bottom, 0.0D, 0.0D, 1.0D);
+            tessellator.addVertexWithUV(this.width, this.bottom, 0.0D, 1.0D, 1.0D);
             tessellator.setColorRGBA_I(0, 0);
-            tessellator.addVertexWithUV(width, bottom - shadowSize, 0.0D, 1.0D, 0.0D);
-            tessellator.addVertexWithUV(0, bottom - shadowSize, 0.0D, 0.0D, 0.0D);
+            tessellator.addVertexWithUV(this.width, this.bottom - shadowSize, 0.0D, 1.0D, 0.0D);
+            tessellator.addVertexWithUV(0, this.bottom - shadowSize, 0.0D, 0.0D, 0.0D);
             tessellator.draw();
 
             GL11.glEnable(GL_TEXTURE_2D);
@@ -259,40 +268,40 @@ public class ScreenPaged
             GL11.glDisable(GL_BLEND);
         }
 
-        overlayBackground(leftWidth, leftWidth + SEPARATOR_WIDTH, top, bottom);
+        this.overlayBackground(this.leftWidth, this.leftWidth + SEPARATOR_WIDTH, this.top, this.bottom);
 
-        drawStringCenteredShadow(fontRenderer, i18n.translateKey(titleTranslationKey), width / 2, 5, 0xffffff);
+        this.drawStringCenteredShadow(this.fontRenderer, i18n.translateKey(this.titleTranslationKey), this.width / 2, 5, 0xffffff);
 
-        drawRightPanelScrollBar(mx, my);
-        drawLeftPanelScrollBar(mx, my);
+        this.drawRightPanelScrollBar(mx, my);
+        this.drawLeftPanelScrollBar(mx, my);
 
         super.render(mx, my, renderPartialTicks);
     }
 
-    protected void drawRightPanelScrollBar(int mouseX, int mouseY) {
-        float totalPageHeight = getTotalRightPanelHeight();
-        float scrollBarHeightPercent = rightScrollRegionHeight / totalPageHeight;
+    protected void drawRightPanelScrollBar(final int mouseX, final int mouseY) {
+        final float totalPageHeight = this.getTotalRightPanelHeight();
+        final float scrollBarHeightPercent = this.rightScrollRegionHeight / totalPageHeight;
 
-        if(scrollBarHeightPercent > 1.0f) return;
+        if (scrollBarHeightPercent > 1.0f) return;
 
         glDisable(GL_TEXTURE_2D);
 
-        int scrollBarX = width - 6;
+        final int scrollBarX = this.width - 6;
 
-        int scrollBarHeightPx = (int) (scrollBarHeightPercent * rightScrollRegionHeight);
-        if(scrollBarHeightPx < 32) {
+        int scrollBarHeightPx = (int) (scrollBarHeightPercent * this.rightScrollRegionHeight);
+        if (scrollBarHeightPx < 32) {
             scrollBarHeightPx = 32;
         }
 
-        float scrollPercent = rightScrollAmount / (totalPageHeight - rightScrollRegionHeight);
+        final float scrollPercent = this.rightScrollAmount / (totalPageHeight - this.rightScrollRegionHeight);
 
-        int scrollBarY = (int) (top + (rightScrollRegionHeight - scrollBarHeightPx) * scrollPercent);
+        final int scrollBarY = (int) (this.top + (this.rightScrollRegionHeight - scrollBarHeightPx) * scrollPercent);
 
-        Tessellator t = Tessellator.instance;
+        final @NotNull Tessellator t = Tessellator.instance;
 
         t.startDrawingQuads();
         t.setColorOpaque(0, 0, 0);
-        t.drawRectangle(scrollBarX, top, 6, rightScrollRegionHeight);
+        t.drawRectangle(scrollBarX, this.top, 6, this.rightScrollRegionHeight);
         t.setColorRGBA_I(0x808080, 255);
         t.drawRectangle(scrollBarX, scrollBarY, 6, scrollBarHeightPx);
         t.setColorRGBA_I(0xc0c0c0, 255);
@@ -301,43 +310,43 @@ public class ScreenPaged
 
         glEnable(GL_TEXTURE_2D);
 
-        if(clickX != null && clickY != null) {
-            if(clickX >= scrollBarX && clickY >= top && clickX <= scrollBarX + 6 && clickY < bottom) {
-                if(oldRightScrollAmount == null) {
-                    oldRightScrollAmount = rightScrollAmount;
+        if (this.clickX != null && this.clickY != null) {
+            if (this.clickX >= scrollBarX && this.clickY >= this.top && this.clickX <= scrollBarX + 6 && this.clickY < this.bottom) {
+                if (this.oldRightScrollAmount == null) {
+                    this.oldRightScrollAmount = this.rightScrollAmount;
                 }
-                rightScrollAmount = oldRightScrollAmount + (clickY - mouseY) * (1.0f / scrollBarHeightPercent) * -1.0f;
-                onScrollRightPanel();
+                this.rightScrollAmount = this.oldRightScrollAmount + (this.clickY - mouseY) * (1.0f / scrollBarHeightPercent) * -1.0f;
+                this.onScrollRightPanel();
             }
-        }else {
-            oldRightScrollAmount = null;
+        } else {
+            this.oldRightScrollAmount = null;
         }
     }
 
-    protected void drawLeftPanelScrollBar(int mouseX, int mouseY) {
-        float totalPagesListHeight = getTotalLeftPanelHeight();
-        float scrollBarHeightPercent = leftScrollRegionHeight / totalPagesListHeight;
+    protected void drawLeftPanelScrollBar(final int mouseX, final int mouseY) {
+        final float totalPagesListHeight = this.getTotalLeftPanelHeight();
+        final float scrollBarHeightPercent = this.leftScrollRegionHeight / totalPagesListHeight;
 
-        if(scrollBarHeightPercent > 1.0f) return;
+        if (scrollBarHeightPercent > 1.0f) return;
 
         glDisable(GL_TEXTURE_2D);
 
-        int scrollBarX = leftWidth - 6;
+        final int scrollBarX = this.leftWidth - 6;
 
-        int scrollBarHeightPx = (int) (scrollBarHeightPercent * leftScrollRegionHeight);
-        if(scrollBarHeightPx < 32) {
+        int scrollBarHeightPx = (int) (scrollBarHeightPercent * this.leftScrollRegionHeight);
+        if (scrollBarHeightPx < 32) {
             scrollBarHeightPx = 32;
         }
 
-        float scrollPercent = leftScrollAmount / (totalPagesListHeight - leftScrollRegionHeight);
+        final float scrollPercent = this.leftScrollAmount / (totalPagesListHeight - this.leftScrollRegionHeight);
 
-        int scrollBarY = (int) (top + (leftScrollRegionHeight - scrollBarHeightPx) * scrollPercent);
+        final int scrollBarY = (int) (this.top + (this.leftScrollRegionHeight - scrollBarHeightPx) * scrollPercent);
 
-        Tessellator t = Tessellator.instance;
+        final @NotNull Tessellator t = Tessellator.instance;
 
         t.startDrawingQuads();
         t.setColorOpaque(0, 0, 0);
-        t.drawRectangle(scrollBarX, top, 6, leftScrollRegionHeight);
+        t.drawRectangle(scrollBarX, this.top, 6, this.leftScrollRegionHeight);
         t.setColorRGBA_I(0x808080, 255);
         t.drawRectangle(scrollBarX, scrollBarY, 6, scrollBarHeightPx);
         t.setColorRGBA_I(0xc0c0c0, 255);
@@ -346,80 +355,78 @@ public class ScreenPaged
 
         glEnable(GL_TEXTURE_2D);
 
-        if(clickX != null && clickY != null) {
-            if(clickX >= scrollBarX && clickY >= top && clickX <= scrollBarX + 6 && clickY < bottom) {
-                if(oldLeftScrollAmount == null) {
-                    oldLeftScrollAmount = leftScrollAmount;
+        if (this.clickX != null && this.clickY != null) {
+            if (this.clickX >= scrollBarX && this.clickY >= this.top && this.clickX <= scrollBarX + 6 && this.clickY < this.bottom) {
+                if (this.oldLeftScrollAmount == null) {
+                    this.oldLeftScrollAmount = this.leftScrollAmount;
                 }
-                leftScrollAmount = oldLeftScrollAmount + (clickY - mouseY) * (1.0f / scrollBarHeightPercent) * -1.0f;
-                onScrollRightPanel();
+                this.leftScrollAmount = this.oldLeftScrollAmount + (this.clickY - mouseY) * (1.0f / scrollBarHeightPercent) * -1.0f;
+                this.onScrollRightPanel();
             }
-        }else {
-            oldLeftScrollAmount = null;
+        } else {
+            this.oldLeftScrollAmount = null;
         }
     }
 
     @Override
-    public void mouseClicked(int mx, int my, int buttonNum)
-    {
+    public void mouseClicked(final int mx, final int my, final int buttonNum) {
         super.mouseClicked(mx, my, buttonNum);
 
-        int left = leftWidth + SEPARATOR_WIDTH + PADDING;
+        final int left = this.leftWidth + SEPARATOR_WIDTH + PADDING;
 
-        if (mx >= leftWidth + SEPARATOR_WIDTH && my >= top && my <= bottom) {
-            int componentY = top - (int) rightScrollAmount;
-            for (PageComponent component : selectedPage.getComponents())
-            {
-                if (mx >= left && mx <= left + pageWidth - PADDING && my >= componentY && my <= componentY + component.getHeight()) {
-                    component.onMouseClick(buttonNum, left, componentY, pageWidth - PADDING, mx - left, my - componentY);
-                    clickedComponent = component;
-                    clickedComponentY = componentY;
+        if (mx >= this.leftWidth + SEPARATOR_WIDTH && my >= this.top && my <= this.bottom) {
+            int componentY = this.top - (int) this.rightScrollAmount;
+            for (final @NotNull PageComponent component : this.selectedPage.getComponents()) {
+                if (mx >= left && mx <= left + this.pageWidth - PADDING && my >= componentY && my <= componentY + component.getHeight()) {
+                    component.onMouseClick(buttonNum, left, componentY, this.pageWidth - PADDING, mx - left, my - componentY);
+                    this.clickedComponent = component;
+                    this.clickedComponentY = componentY;
                     break;
                 }
                 componentY += component.getHeight();
             }
-        } else if (mx >= 0 && mx <= leftWidth && my >= top && my <= bottom) {
-            int pagesListHeight = getTotalLeftPanelHeight();
-            int pagesListY = top - (int) leftScrollAmount;
-            if (pagesListHeight < bottom - top) {
-                pagesListY = top + (bottom - top - pagesListHeight) / 2;
+        } else if (mx >= 0 && mx <= this.leftWidth && my >= this.top && my <= this.bottom) {
+            final int pagesListHeight = this.getTotalLeftPanelHeight();
+            int pagesListY = this.top - (int) this.leftScrollAmount;
+            if (pagesListHeight < this.bottom - this.top) {
+                pagesListY = this.top + (this.bottom - this.top - pagesListHeight) / 2;
             }
-            for(Page page : pageRegistry.getPages()) {
-                if (mx >= 0 && mx <= leftWidth && my >= pagesListY && my <= pagesListY + PAGE_BUTTON_HEIGHT) {
-                    rightScrollAmount = 0;
-                    selectedPage = page;
-                    this.selectedPage.initComponents(mc);
-                    mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
-                    mc.texturePackList.refreshIfReady();
+            for (final @NotNull Page page : this.pageRegistry.getPages()) {
+                if (mx >= 0 && mx <= this.leftWidth && my >= pagesListY && my <= pagesListY + PAGE_BUTTON_HEIGHT) {
+                    this.rightScrollAmount = 0;
+                    this.selectedPage = page;
+                    this.selectedPage.initComponents(this.mc);
+                    this.mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+                    this.mc.texturePackList.refreshIfReady();
                     break;
                 }
                 pagesListY += PAGE_BUTTON_HEIGHT;
             }
         }
 
-        clickX = mx;
-        clickY = my;
+        this.clickX = mx;
+        this.clickY = my;
     }
 
     @Override
-    public void mouseReleased(int mx, int my, int buttonNum) {
+    public void mouseReleased(final int mx, final int my, final int buttonNum) {
         super.mouseReleased(mx, my, buttonNum);
 
-        int left = leftWidth + SEPARATOR_WIDTH + PADDING;
-        if (my >= top && my <= bottom) {
-            if (clickedComponent != null) {
+        final int left = this.leftWidth + SEPARATOR_WIDTH + PADDING;
+        if (my >= this.top && my <= this.bottom) {
+            if (this.clickedComponent != null) {
                 if (buttonNum >= 0) {
-                    clickedComponent.onMouseRelease(buttonNum, left, clickedComponentY, pageWidth, mx - left, my - clickedComponentY);
-                    clickedComponent = null;
+                    this.clickedComponent.onMouseRelease(buttonNum, left, this.clickedComponentY, this.pageWidth, mx - left, my - this.clickedComponentY);
+                    this.clickedComponent = null;
                 } else {
-                    clickedComponent.onMouseMove(left, clickedComponentY, pageWidth, mx - left, my - clickedComponentY);
+                    this.clickedComponent.onMouseMove(left, this.clickedComponentY, this.pageWidth, mx - left, my - this.clickedComponentY);
                 }
             }
         }
 
-        if(buttonNum >= 0) {
-            clickX = null;
-            clickY = null;
+        if (buttonNum >= 0) {
+            this.clickX = null;
+            this.clickY = null;
         }
     }
 
@@ -427,43 +434,38 @@ public class ScreenPaged
     public void renderBackground() {
         super.renderBackground();
 
-        if (mc.currentWorld == null)
-        {
-            Tessellator tessellator = Tessellator.instance;
-            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
+        if (this.mc.currentWorld == null) {
+            final @NotNull Tessellator tessellator = Tessellator.instance;
+            this.mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
             GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-            float scale = 32F;
+            final float scale = 32F;
             tessellator.startDrawingQuads();
             tessellator.setColorOpaque_I(0x202020);
 
-            tessellator.addVertexWithUV(0, bottom, 0.0D, 0, (float)(bottom + (int) rightScrollAmount) / scale);
-            tessellator.addVertexWithUV(width, bottom, 0.0D, (float)width / scale, (float)(bottom + (int) rightScrollAmount) / scale);
-            tessellator.addVertexWithUV(width, top, 0.0D, (float)width / scale, (float)(top + (int) rightScrollAmount) / scale);
-            tessellator.addVertexWithUV(0, top, 0.0D, 0, (float)(top + (int) rightScrollAmount) / scale);
+            tessellator.addVertexWithUV(0, this.bottom, 0.0D, 0, (float) (this.bottom + (int) this.rightScrollAmount) / scale);
+            tessellator.addVertexWithUV(this.width, this.bottom, 0.0D, (float) this.width / scale, (float) (this.bottom + (int) this.rightScrollAmount) / scale);
+            tessellator.addVertexWithUV(this.width, this.top, 0.0D, (float) this.width / scale, (float) (this.top + (int) this.rightScrollAmount) / scale);
+            tessellator.addVertexWithUV(0, this.top, 0.0D, 0, (float) (this.top + (int) this.rightScrollAmount) / scale);
 
-            tessellator.addVertexWithUV(0, bottom, 0.0D, 0, (float)(bottom + (int) leftScrollAmount) / scale);
-            tessellator.addVertexWithUV(leftWidth, bottom, 0.0D, (float) leftWidth / scale, (float)(bottom + (int) leftScrollAmount) / scale);
-            tessellator.addVertexWithUV(leftWidth, top, 0.0D, (float) leftWidth / scale, (float)(top + (int) leftScrollAmount) / scale);
-            tessellator.addVertexWithUV(0, top, 0.0D, 0, (float)(top + (int) leftScrollAmount) / scale);
+            tessellator.addVertexWithUV(0, this.bottom, 0.0D, 0, (float) (this.bottom + (int) this.leftScrollAmount) / scale);
+            tessellator.addVertexWithUV(this.leftWidth, this.bottom, 0.0D, (float) this.leftWidth / scale, (float) (this.bottom + (int) this.leftScrollAmount) / scale);
+            tessellator.addVertexWithUV(this.leftWidth, this.top, 0.0D, (float) this.leftWidth / scale, (float) (this.top + (int) this.leftScrollAmount) / scale);
+            tessellator.addVertexWithUV(0, this.top, 0.0D, 0, (float) (this.top + (int) this.leftScrollAmount) / scale);
 
             tessellator.draw();
-        }
-        else
-        {
-            drawRect(0, 0, width, top, 0x5F000000);
-            drawRect(0, bottom, width, height, 0x5F000000);
-            drawRect(leftWidth, top, leftWidth + SEPARATOR_WIDTH, bottom, 0x5F000000);
+        } else {
+            this.drawRect(0, 0, this.width, this.top, 0x5F000000);
+            this.drawRect(0, this.bottom, this.width, this.height, 0x5F000000);
+            this.drawRect(this.leftWidth, this.top, this.leftWidth + SEPARATOR_WIDTH, this.bottom, 0x5F000000);
         }
     }
 
-    private void overlayBackground(int minX, int maxX, int minY, int maxY)
-    {
-        if (mc.currentWorld == null)
-        {
-            Tessellator tessellator = Tessellator.instance;
-            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
+    private void overlayBackground(final int minX, final int maxX, final int minY, final int maxY) {
+        if (this.mc.currentWorld == null) {
+            final @NotNull Tessellator tessellator = Tessellator.instance;
+            this.mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
             GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-            float scale = 32F;
+            final float scale = 32F;
             tessellator.startDrawingQuads();
             tessellator.setColorOpaque_I(0x404040);
             tessellator.addVertexWithUV(minX, maxY, 0.0D, (float) minX / scale, (float) maxY / scale);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonComponent.java
index ba0d2afed..a2e461450 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonComponent.java
@@ -3,30 +3,29 @@ package net.minecraft.client.gui.popup;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 public class ButtonComponent
     extends InteractivePopupComponent<Integer> {
-    private final Minecraft minecraft;
-    private final String buttonLabel;
-    private final String[] buttonValues;
-    private final ButtonElement button;
+    private final @NotNull Minecraft minecraft = Minecraft.getMinecraft();
+    private final @NotNull String buttonLabel;
+    private final @NotNull String @NotNull [] buttonValues;
+    private final @NotNull ButtonElement button;
     private int value;
 
-    public ButtonComponent(int width, String buttonLabel, String[] buttonValues, int defaultValue) {
+    public ButtonComponent(final int width, final @NotNull String buttonLabel, final @NotNull String @NotNull [] buttonValues, final int defaultValue) {
         super(width);
 
         this.buttonLabel = buttonLabel;
         this.buttonValues = buttonValues;
 
-        this.minecraft = Minecraft.getMinecraft();
-
         this.value = defaultValue;
 
-        button = new ButtonElement(0, 0, 0, width, getHeight(), getButtonLabel());
+        this.button = new ButtonElement(0, 0, 0, width, this.getHeight(), this.getButtonLabel());
     }
 
-    private String getButtonLabel() {
-        return I18n.getInstance().translateKeyAndFormat(buttonLabel, I18n.getInstance().translateKey(buttonValues[value]));
+    private @NotNull String getButtonLabel() {
+        return I18n.getInstance().translateKeyAndFormat(this.buttonLabel, I18n.getInstance().translateKey(this.buttonValues[this.value]));
     }
 
     @Override
@@ -35,22 +34,22 @@ public class ButtonComponent
     }
 
     @Override
-    public void render(int x, int y, int mouseX, int mouseY) {
-        button.xPosition = x;
-        button.yPosition = y;
-        button.drawButton(minecraft, mouseX, mouseY);
+    public void render(final int x, final int y, final int mouseX, final int mouseY) {
+        this.button.xPosition = x;
+        this.button.yPosition = y;
+        this.button.drawButton(this.minecraft, mouseX, mouseY);
     }
 
     @Override
-    public void onClick(int x, int y, int button) {
-        if (this.button.mouseClicked(minecraft, x, y)) {
-            value = (value + 1) % buttonValues.length;
-            this.button.displayString = getButtonLabel();
+    public void onClick(final int x, final int y, final int button) {
+        if (this.button.mouseClicked(this.minecraft, x, y)) {
+            this.value = (this.value + 1) % this.buttonValues.length;
+            this.button.displayString = this.getButtonLabel();
         }
     }
 
     @Override
-    public Integer getOutput() {
-        return value;
+    public @NotNull Integer getOutput() {
+        return this.value;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonGroupComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonGroupComponent.java
index 542085474..108f9e430 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonGroupComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/ButtonGroupComponent.java
@@ -3,61 +3,53 @@ package net.minecraft.client.gui.popup;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.core.sound.SoundCategory;
+import org.jetbrains.annotations.NotNull;
 
 public class ButtonGroupComponent
-    extends PopupComponent
-{
+    extends PopupComponent {
     private static final int BUTTON_GAP = 2;
-    private final Minecraft minecraft;
-    private final ButtonElement[] buttons;
+    private final @NotNull Minecraft minecraft = Minecraft.getMinecraft();
+    private final @NotNull ButtonElement @NotNull [] buttons;
 
-    public ButtonGroupComponent(int width, String[] buttonLabels, int[] buttonStatusCodes, boolean[] enabled)
-    {
+    public ButtonGroupComponent(final int width, final @NotNull String @NotNull [] buttonLabels, final int @NotNull [] buttonStatusCodes, final boolean @NotNull [] enabled) {
         super(width);
 
-        this.minecraft = Minecraft.getMinecraft();
-
         this.buttons = new ButtonElement[buttonLabels.length];
 
-        int numButtons = this.buttons.length;
+        final int numButtons = this.buttons.length;
         int buttonWidth = (width - (BUTTON_GAP * (numButtons - 1))) / numButtons;
         if (numButtons == 1) buttonWidth = width;
-        buttonWidth = Math.min(buttonWidth,256);
-        for (int i = 0; i < numButtons; i++)
-        {
-            buttons[i] = new ButtonElement(buttonStatusCodes[i], 0, 0, buttonWidth, getHeight(), buttonLabels[i]);
-            buttons[i].enabled = enabled[i];
+        buttonWidth = Math.min(buttonWidth, 256);
+        for (int i = 0; i < numButtons; i++) {
+            this.buttons[i] = new ButtonElement(buttonStatusCodes[i], 0, 0, buttonWidth, this.getHeight(), buttonLabels[i]);
+            this.buttons[i].enabled = enabled[i];
         }
     }
 
     @Override
-    public int getHeight()
-    {
+    public int getHeight() {
         return 20;
     }
 
     @Override
-    public void render(int x, int y, int mouseX, int mouseY)
-    {
-        for (int i = 0; i < buttons.length; i++)
-        {
-            ButtonElement button = buttons[i];
+    public void render(final int x, final int y, final int mouseX, final int mouseY) {
+        for (int i = 0; i < this.buttons.length; i++) {
+            final @NotNull ButtonElement button = this.buttons[i];
 
             button.xPosition = x + (button.width + BUTTON_GAP) * i;
             button.yPosition = y;
-            button.drawButton(minecraft, mouseX, mouseY);
+            button.drawButton(this.minecraft, mouseX, mouseY);
         }
     }
 
     @Override
-    public void onClick(int x, int y, int button)
-    {
-        for (ButtonElement b : buttons)
-        {
-            if (b.mouseClicked(minecraft, x, y))
-            {
-                getParent().close(b.id);
-                minecraft.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+    public void onClick(final int x, final int y, final int button) {
+        for (final @NotNull ButtonElement b : this.buttons) {
+            if (b.mouseClicked(this.minecraft, x, y)) {
+                if (this.getParent() != null) {
+                    this.getParent().close(b.id);
+                }
+                this.minecraft.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
                 return;
             }
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/InteractivePopupComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/InteractivePopupComponent.java
index bd6c8e22b..3c90cb65b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/InteractivePopupComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/InteractivePopupComponent.java
@@ -1,12 +1,14 @@
 package net.minecraft.client.gui.popup;
 
+import org.jetbrains.annotations.NotNull;
+
 public abstract class InteractivePopupComponent<T>
     extends PopupComponent
 {
-    public InteractivePopupComponent(int width)
+    public InteractivePopupComponent(final int width)
     {
         super(width);
     }
 
-    public abstract T getOutput();
+    public abstract @NotNull T getOutput();
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/LabelComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/LabelComponent.java
index 03cf664d0..51724cd09 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/LabelComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/LabelComponent.java
@@ -3,30 +3,29 @@ package net.minecraft.client.gui.popup;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.tessellator.Tessellator;
+import org.jetbrains.annotations.NotNull;
 
 public class LabelComponent
-    extends PopupComponent
-{
-    private final FontRenderer fontRenderer;
-    private final String text;
+    extends PopupComponent {
+    private final @NotNull FontRenderer fontRenderer = Minecraft.getMinecraft().font;
+    private final @NotNull String text;
     private final int color;
 
-    public LabelComponent(final int width, final String text, final int color) {
+    public LabelComponent(final int width, final @NotNull String text, final int color) {
         super(width);
-        this.fontRenderer = Minecraft.getMinecraft().font;
+
         this.text = text;
         this.color = color;
     }
 
     @Override
-    public int getHeight()
-    {
+    public int getHeight() {
         return 12;
     }
 
     @Override
     public void render(final int x, final int y, final int mouseX, final int mouseY) {
-        final int middle = (x - PopupScreen.HORIZONTAL_MARGIN) + getWidth() / 2;
+        final int middle = (x - PopupScreen.HORIZONTAL_MARGIN) + this.getWidth() / 2;
         this.fontRenderer.renderCentered(Tessellator.instance, this.text, middle, y).setShadow().setColor(this.color).call();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/ListComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/ListComponent.java
index 577996205..1a4d1c1ec 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/ListComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/ListComponent.java
@@ -3,6 +3,8 @@ package net.minecraft.client.gui.popup;
 import net.minecraft.client.render.Scissor;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.sound.SoundCategory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 
@@ -12,19 +14,18 @@ import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.core.util.helper.MathHelper;
 
 public class ListComponent
-    extends InteractivePopupComponent<Integer>
-{
-    private final Minecraft minecraft;
-    private int selectedItem = 0;
+    extends InteractivePopupComponent<Integer> {
+    private final @NotNull Minecraft minecraft = Minecraft.getMinecraft();
+    private int selectedItem;
     private float scrollAmount = 0;
-    private final ButtonElement[] buttons;
+    private final @NotNull ButtonElement @NotNull [] buttons;
     private final int height;
     private int lastX = 0;
     private int lastY = 0;
     private final boolean closeOnItemSelected;
-    private final TooltipElement tooltip;
-    private final String[] buttonTooltips;
-    
+    private final @NotNull TooltipElement tooltip;
+    private final @NotNull String @Nullable [] buttonTooltips;
+
     private int scrollbarX;
     private int scrollbarY;
     private int scrollbarWidth;
@@ -32,170 +33,154 @@ public class ListComponent
     private boolean isScrolling = false;
     private int clickY;
     private float previousScrollAmount = 0.0f;
-    
-    public ListComponent(int width, int height, String[] buttonLabels, String[] buttonTooltips, int selectedItem, boolean closeOnItemSelected)
-    {
+
+    public ListComponent(
+        final int width,
+        final int height,
+        final @NotNull String @NotNull [] buttonLabels,
+        final @NotNull String @Nullable [] buttonTooltips,
+        final int selectedItem,
+        final boolean closeOnItemSelected
+    ) {
         super(width);
 
-        this.minecraft = Minecraft.getMinecraft();
         this.height = height;
         this.closeOnItemSelected = closeOnItemSelected;
-        this.tooltip = new TooltipElement(minecraft);
+        assert this.minecraft != null;
+        this.tooltip = new TooltipElement(this.minecraft);
 
         this.selectedItem = selectedItem;
         this.buttonTooltips = buttonTooltips;
 
         this.buttons = new ButtonElement[buttonLabels.length];
-        for (int i = 0; i < this.buttons.length; i++)
-        {
+        for (int i = 0; i < this.buttons.length; i++) {
             this.buttons[i] = new ButtonElement(i, 0, 0, width - 2 - 6, 20, buttonLabels[i]);
-            if (i == selectedItem)
-            {
+            if (i == selectedItem) {
                 this.buttons[i].enabled = false;
             }
         }
 
         // Scroll so selected item is in view
-        float ratio = (float)(getScrollableHeight() + this.height) / getScrollableHeight();
-        float sc = (selectedItem / (float)(this.buttons.length - 4)) * ratio;
-        sc -= ((float)this.height / getScrollableHeight());
-        scroll(sc);
+        final float ratio = (float) (this.getScrollableHeight() + this.height) / this.getScrollableHeight();
+        float sc = (selectedItem / (float) (this.buttons.length - 4)) * ratio;
+        sc -= ((float) this.height / this.getScrollableHeight());
+        this.scroll(sc);
     }
 
-    private boolean canScroll()
-    {
-        return getScrollableHeight() > height - 2;
+    private boolean canScroll() {
+        return this.getScrollableHeight() > this.height - 2;
     }
 
     @Override
-    public Integer getOutput()
-    {
+    public @NotNull Integer getOutput() {
         return this.selectedItem;
     }
 
     @Override
-    public int getHeight()
-    {
-        return height;
+    public int getHeight() {
+        return this.height;
     }
 
-    private void scroll(float amount)
-    {
-        if (!canScroll()) {
-            scrollAmount = 0.0f;
+    private void scroll(final float amount) {
+        if (!this.canScroll()) {
+            this.scrollAmount = 0.0f;
         } else {
-            scrollAmount = MathHelper.clamp(scrollAmount + amount, 0.0f, 1.0f);
+            this.scrollAmount = MathHelper.clamp(this.scrollAmount + amount, 0.0f, 1.0f);
         }
     }
 
     @Override
-    public void render(int x, int y, int mouseX, int mouseY)
-    {
+    public void render(final int x, final int y, final int mouseX, final int mouseY) {
         this.lastX = x;
         this.lastY = y;
 
         // Do scroll
-        if (canScroll() && mouseInRegion(x, y, mouseX, mouseY))
-        {
-            float wheel = Mouse.getDWheel();
+        if (this.canScroll() && this.mouseInRegion(x, y, mouseX, mouseY)) {
+            final float wheel = Mouse.getDWheel();
             if (wheel != 0.0f)
-                scroll(wheel / -12.0f);
+                this.scroll(wheel / -12.0f);
         }
 
         GL11.glDisable(GL11.GL_TEXTURE_2D);
-        drawBackground(x, y);
-        drawScrollbar(x, y, mouseX, mouseY);
+        this.drawBackground(x, y);
+        this.drawScrollbar(x, y, mouseY);
 
-        Scissor.enable(x + 1, y + 1, getWidth() - 2, getHeight() - 2);
+        Scissor.enable(x + 1, y + 1, this.getWidth() - 2, this.getHeight() - 2);
         GL11.glEnable(GL11.GL_TEXTURE_2D);
 
         // Draw buttons
-        for (int i = 0; i < buttons.length; i++)
-        {
-            if (canScroll()) {
-                buttons[i].width = getWidth() - 2 - 6;
+        for (int i = 0; i < this.buttons.length; i++) {
+            if (this.canScroll()) {
+                this.buttons[i].width = this.getWidth() - 2 - 6;
             } else {
-                buttons[i].width = getWidth() - 2;
+                this.buttons[i].width = this.getWidth() - 2;
             }
 
-            ButtonElement button = buttons[i];
+            final ButtonElement button = this.buttons[i];
             button.xPosition = x + 1;
-            button.yPosition = (y + 1) + (i * 20) - getScrollPixels();
-            if (mouseInRegion(x, y, mouseX, mouseY))
-            {
-                button.drawButton(minecraft, mouseX, mouseY);
-            }
-            else
-            {
-                button.drawButton(minecraft, -1, -1);
+            button.yPosition = (y + 1) + (i * 20) - this.getScrollPixels();
+            if (this.mouseInRegion(x, y, mouseX, mouseY)) {
+                button.drawButton(this.minecraft, mouseX, mouseY);
+            } else {
+                button.drawButton(this.minecraft, -1, -1);
             }
         }
 
         Scissor.disable();
 
-        if (buttonTooltips != null && mouseInRegion(x, y, mouseX, mouseY))
-        {
-            for (int i = 0; i < buttons.length; i++)
-            {
-                ButtonElement button = buttons[i];
-                if (button.isHovered(mouseX, mouseY))
-                {
-                    tooltip.render(buttonTooltips[i], mouseX, mouseY, 0, 0);
+        if (this.buttonTooltips != null && this.mouseInRegion(x, y, mouseX, mouseY)) {
+            for (int i = 0; i < this.buttons.length; i++) {
+                final ButtonElement button = this.buttons[i];
+                if (button.isHovered(mouseX, mouseY)) {
+                    this.tooltip.render(this.buttonTooltips[i], mouseX, mouseY, 0, 0);
                     break;
                 }
             }
         }
     }
 
-    private boolean mouseInRegion(int x, int y, int mouseX, int mouseY)
-    {
-        return mouseX >= x && mouseX < x + getWidth() && mouseY >= y && mouseY < y + height;
+    private boolean mouseInRegion(final int x, final int y, final int mouseX, final int mouseY) {
+        return mouseX >= x && mouseX < x + this.getWidth() && mouseY >= y && mouseY < y + this.height;
     }
 
-    private int getScrollPixels()
-    {
-        return (int)(scrollAmount * (getScrollableHeight() - (height - 2)));
+    private int getScrollPixels() {
+        return (int) (this.scrollAmount * (this.getScrollableHeight() - (this.height - 2)));
     }
 
-    private int getScrollableHeight()
-    {
-        return 20 * buttons.length;
+    private int getScrollableHeight() {
+        return 20 * this.buttons.length;
     }
 
     @Override
-    public void onClick(int x, int y, int button)
-    {
+    public void onClick(final int x, final int y, final int button) {
         super.onClick(x, y, button);
 
-        int scrollableHeight = getScrollableHeight();
-        int displayRegionHeight = height - 2;
-        boolean canScroll = scrollableHeight > displayRegionHeight;
+        final int scrollableHeight = this.getScrollableHeight();
+        final int displayRegionHeight = this.height - 2;
+        final boolean canScroll = scrollableHeight > displayRegionHeight;
 
-        if(canScroll && button == 0 && x >= scrollbarX && x < scrollbarX + scrollbarWidth && y >= scrollbarY && y < scrollbarY + scrollbarHeight) {
-        	isScrolling = true;
-        	previousScrollAmount = scrollAmount;
-        	clickY = y;
-        	return;
+        if (canScroll && button == 0 && x >= this.scrollbarX && x < this.scrollbarX + this.scrollbarWidth && y >= this.scrollbarY && y < this.scrollbarY + this.scrollbarHeight) {
+            this.isScrolling = true;
+            this.previousScrollAmount = this.scrollAmount;
+            this.clickY = y;
+            return;
         }
-        
-        if (mouseInRegion(lastX, lastY, x, y))
-        {
-            for (ButtonElement b : this.buttons)
-            {
-                if (b.mouseClicked(minecraft, x, y))
-                {
-                    for (ButtonElement b2 : this.buttons)
-                    {
+
+        if (this.mouseInRegion(this.lastX, this.lastY, x, y)) {
+            for (final ButtonElement b : this.buttons) {
+                if (b.mouseClicked(this.minecraft, x, y)) {
+                    for (final ButtonElement b2 : this.buttons) {
                         b2.enabled = true;
                     }
 
                     b.enabled = false;
                     this.selectedItem = b.id;
 
-                    if (closeOnItemSelected)
-                    {
-                        getParent().close(1);
-                        minecraft.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
+                    if (this.closeOnItemSelected) {
+                        if (this.getParent() != null) {
+                            this.getParent().close(1);
+                        }
+                        this.minecraft.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
                     }
 
                     break;
@@ -203,76 +188,73 @@ public class ListComponent
             }
         }
     }
-    
+
     @Override
-    public void mouseMovedOrUp(int x, int y, int button)
-    {
-    	super.mouseMovedOrUp(x, y, button);
-    	if(button == 0) {
-    		isScrolling = false;
-    		previousScrollAmount = 0.0f;
-    		clickY = 0;
-    	}
+    public void mouseMovedOrUp(final int x, final int y, final int button) {
+        super.mouseMovedOrUp(x, y, button);
+        if (button == 0) {
+            this.isScrolling = false;
+            this.previousScrollAmount = 0.0f;
+            this.clickY = 0;
+        }
     }
 
-    private void drawBackground(int x, int y)
-    {
-        Tessellator tessellator = Tessellator.instance;
+    private void drawBackground(final int x, final int y) {
+        final @NotNull Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
         tessellator.setColorOpaque_I(0xA0A0A0);
-        tessellator.addVertex(x, y + height, 0.0D);
-        tessellator.addVertex(x + getWidth(), y + height, 0.0D);
-        tessellator.addVertex(x + getWidth(), y, 0.0D);
+        tessellator.addVertex(x, y + this.height, 0.0D);
+        tessellator.addVertex(x + this.getWidth(), y + this.height, 0.0D);
+        tessellator.addVertex(x + this.getWidth(), y, 0.0D);
         tessellator.addVertex(x, y, 0.0D);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setColorOpaque_I(0x000000);
-        tessellator.addVertex(x + 1, y + height - 1, 0.0D);
-        tessellator.addVertex(x + getWidth() - 1, y + height - 1, 0.0D);
-        tessellator.addVertex(x + getWidth() - 1, y + 1, 0.0D);
+        tessellator.addVertex(x + 1, y + this.height - 1, 0.0D);
+        tessellator.addVertex(x + this.getWidth() - 1, y + this.height - 1, 0.0D);
+        tessellator.addVertex(x + this.getWidth() - 1, y + 1, 0.0D);
         tessellator.addVertex(x + 1, y + 1, 0.0D);
         tessellator.draw();
     }
 
-    private void drawScrollbar(int x, int y, int mouseX, int mouseY)
-    {
-    	int scrollableHeight = getScrollableHeight();
-        int displayRegionHeight = height - 2;
+    private void drawScrollbar(final int x, final int y, final int mouseY) {
+        final int scrollableHeight = this.getScrollableHeight();
+        final int displayRegionHeight = this.height - 2;
 
-        if (!canScroll()) {
-        	return;
+        if (!this.canScroll()) {
+            return;
         }
 
-        float scrollbarScale = (float) displayRegionHeight / scrollableHeight;
-        
-    	scrollbarWidth = 6;
-        scrollbarHeight = (int) (scrollbarScale * displayRegionHeight);
-        
-        int minScrollbarY = 0;
-        int maxScrollbarY = displayRegionHeight - scrollbarHeight;
-        
-        int scrollbarDelta = maxScrollbarY - minScrollbarY;
-        
-        scrollbarY = y + 1 + (int) (scrollAmount * scrollbarDelta);
-        scrollbarX = x + getWidth() - 1 - 6;
-        
-        Tessellator t = Tessellator.instance;
+        final float scrollbarScale = (float) displayRegionHeight / scrollableHeight;
+
+        this.scrollbarWidth = 6;
+        this.scrollbarHeight = (int) (scrollbarScale * displayRegionHeight);
+
+        final int minScrollbarY = 0;
+        final int maxScrollbarY = displayRegionHeight - this.scrollbarHeight;
+
+        final int scrollbarDelta = maxScrollbarY - minScrollbarY;
+
+        this.scrollbarY = y + 1 + (int) (this.scrollAmount * scrollbarDelta);
+        this.scrollbarX = x + this.getWidth() - 1 - 6;
+
+        final Tessellator t = Tessellator.instance;
 
         t.startDrawingQuads();
         t.setColorRGBA_I(0x808080, 255);
-        t.drawRectangle(scrollbarX, scrollbarY, 6, scrollbarHeight);
+        t.drawRectangle(this.scrollbarX, this.scrollbarY, 6, this.scrollbarHeight);
         t.setColorRGBA_I(0xc0c0c0, 255);
-        t.drawRectangle(scrollbarX, scrollbarY, 5, scrollbarHeight - 1);
+        t.drawRectangle(this.scrollbarX, this.scrollbarY, 5, this.scrollbarHeight - 1);
         t.draw();
-        
-        if(isScrolling) {
-        	int delta = mouseY - clickY;
-        	float scrolledScreens = delta / (float) scrollbarHeight;
-        	float scrolledPixels = displayRegionHeight * scrolledScreens;
-        	float scrolledAmount = scrolledPixels / (float) (scrollableHeight - displayRegionHeight);
-        	
-        	scrollAmount = MathHelper.clamp(previousScrollAmount + scrolledAmount, 0.0f, 1.0f);
+
+        if (this.isScrolling) {
+            final int delta = mouseY - this.clickY;
+            final float scrolledScreens = delta / (float) this.scrollbarHeight;
+            final float scrolledPixels = displayRegionHeight * scrolledScreens;
+            final float scrolledAmount = scrolledPixels / (float) (scrollableHeight - displayRegionHeight);
+
+            this.scrollAmount = MathHelper.clamp(this.previousScrollAmount + scrolledAmount, 0.0f, 1.0f);
         }
-        
+
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/MessageBoxComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/MessageBoxComponent.java
index 8d2dc435e..22eba8002 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/MessageBoxComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/MessageBoxComponent.java
@@ -5,6 +5,7 @@ import net.minecraft.client.render.Scissor;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 
@@ -13,12 +14,11 @@ import java.util.Arrays;
 import java.util.List;
 
 public class MessageBoxComponent
-    extends PopupComponent
-{
+    extends PopupComponent {
     private static final String FORMAT_REGEX = "[" + TextFormatting.FORMAT_CHARS + "]";
-    private final Minecraft minecraft;
+    private final @NotNull Minecraft minecraft = Minecraft.getMinecraft();
     private float scrollAmount = 0;
-    private final List<String> lines = new ArrayList<>();
+    private final @NotNull List<@NotNull String> lines = new ArrayList<>();
     private final int height;
 
     private int scrollbarX;
@@ -29,33 +29,31 @@ public class MessageBoxComponent
     private int clickY;
     private float previousScrollAmount = 0.0f;
 
-    public MessageBoxComponent(int width, int height, String text, int chars)
-    {
+    public MessageBoxComponent(final int width, final int height, final @NotNull String text, final int chars) {
         super(width);
 
-        this.minecraft = Minecraft.getMinecraft();
         this.height = height;
 
-        setupText(text, chars);
+        this.setupText(text, chars);
     }
 
-    private void setupText(String text, int limit) {
-        lines.clear();
+    private void setupText(final @NotNull String text, final int limit) {
+        this.lines.clear();
 
-        List<String> completeSplit = new ArrayList<>(); //the processed wrapped text, each entry is one line
-        ArrayList<String> newlineSplit = new ArrayList<>(Arrays.asList(text.split("\\n"))); //text split based only on newlines before processing
+        final @NotNull List<@NotNull String> completeSplit = new ArrayList<>(); //the processed wrapped text, each entry is one line
+        final @NotNull ArrayList<@NotNull String> newlineSplit = new ArrayList<>(Arrays.asList(text.split("\\n"))); //text split based only on newlines before processing
 
-        String lastFormat = "";
+        @NotNull String lastFormat = "";
 
-        for (String s : newlineSplit) {
-            ArrayList<String> words = new ArrayList<>(Arrays.asList(s.split(" ")));
-            ArrayList<String> limitedSizeWords = new ArrayList<>(); //all words here should not be larger than the limit
-            StringBuilder line = new StringBuilder();
+        for (final @NotNull String s : newlineSplit) {
+            final @NotNull ArrayList<@NotNull String> words = new ArrayList<>(Arrays.asList(s.split(" ")));
+            final @NotNull ArrayList<@NotNull String> limitedSizeWords = new ArrayList<>(); //all words here should not be larger than the limit
+            @NotNull StringBuilder line = new StringBuilder();
             line.append(lastFormat);
             //split words larger than the limit into multiple that can fit
-            for (String word : words) {
+            for (final @NotNull String word : words) {
                 if (word.length() > limit) {
-                    ArrayList<String> split = new ArrayList<>();
+                    final @NotNull ArrayList<@NotNull String> split = new ArrayList<>();
                     for (int j = 0; j <= word.length() / limit; j++) {
                         split.add(word.substring(j * limit, Math.min((j + 1) * limit, word.length())));
                     }
@@ -64,12 +62,12 @@ public class MessageBoxComponent
                     limitedSizeWords.add(word);
                 }
             }
-            for (String word : limitedSizeWords) {
-                String currentFormat = "";
+            for (final @NotNull String word : limitedSizeWords) {
+                @NotNull String currentFormat = "";
                 //check for formatting and extract it
                 if (word.contains("§")) {
                     if (word.indexOf('§') < word.length() - 1) {
-                        String format = String.valueOf(word.charAt(word.indexOf('§') + 1));
+                        final @NotNull String format = String.valueOf(word.charAt(word.indexOf('§') + 1));
                         if (format.matches(FORMAT_REGEX)) { //if matches any valid text format
                             currentFormat = "§" + format;
                         }
@@ -85,145 +83,132 @@ public class MessageBoxComponent
                     line.append(lastFormat);
                     line.append(word).append(" ");
                 }
-                if(!currentFormat.isEmpty()) lastFormat = currentFormat; //change last format if a new one was found in this iteration
+                if (!currentFormat.isEmpty())
+                    lastFormat = currentFormat; //change last format if a new one was found in this iteration
             }
             completeSplit.add(line.toString());
         }
 
-        lines.addAll(completeSplit);
+        this.lines.addAll(completeSplit);
     }
 
     @Override
-    public int getHeight()
-    {
-        return height;
+    public int getHeight() {
+        return this.height;
     }
 
-    private void scroll(float amount)
-    {
-        scrollAmount = MathHelper.clamp(scrollAmount + amount, 0.0f, 1.0f);
+    private void scroll(final float amount) {
+        this.scrollAmount = MathHelper.clamp(this.scrollAmount + amount, 0.0f, 1.0f);
     }
 
     @Override
-    public void render(int x, int y, int mouseX, int mouseY)
-    {
-
+    public void render(final int x, final int y, final int mouseX, final int mouseY) {
         // Do scroll
-        if (mouseInRegion(x, y, mouseX, mouseY))
-        {
-            float wheel = Mouse.getDWheel();
+        if (this.mouseInRegion(x, y, mouseX, mouseY)) {
+            final float wheel = Mouse.getDWheel();
             if (wheel != 0.0f)
-                scroll(wheel / -12.0f);
+                this.scroll(wheel / -12.0f);
         }
 
         GL11.glDisable(GL11.GL_TEXTURE_2D);
-        drawBackground(x, y);
-        drawScrollbar(x, y, mouseX, mouseY);
+        this.drawBackground(x, y);
+        this.drawScrollbar(x, y, mouseX, mouseY);
 
-        Scissor.enable(x + 1, y + 1, getWidth() - 2, getHeight() - 2);
+        Scissor.enable(x + 1, y + 1, this.getWidth() - 2, this.getHeight() - 2);
         GL11.glEnable(GL11.GL_TEXTURE_2D);
 
         // Draw lines
-        for (int i = 0; i < lines.size(); i++)
-        {
-            this.minecraft.font.render(Tessellator.instance, lines.get(i),x + 4,(y + 4) + (i * 12) - getScrollPixels()).setShadow().call();
+        for (int i = 0; i < this.lines.size(); i++) {
+            this.minecraft.font.render(Tessellator.instance, this.lines.get(i), x + 4, (y + 4) + (i * 12) - this.getScrollPixels()).setShadow().call();
         }
 
         Scissor.disable();
     }
 
-    private boolean mouseInRegion(int x, int y, int mouseX, int mouseY)
-    {
-        return mouseX >= x && mouseX < x + getWidth() && mouseY >= y && mouseY < y + height;
+    private boolean mouseInRegion(final int x, final int y, final int mouseX, final int mouseY) {
+        return mouseX >= x && mouseX < x + this.getWidth() && mouseY >= y && mouseY < y + this.height;
     }
 
-    private int getScrollPixels()
-    {
-        return (int)(scrollAmount * (getScrollableHeight() - (height - 2)));
+    private int getScrollPixels() {
+        return (int) (this.scrollAmount * (this.getScrollableHeight() - (this.height - 2)));
     }
 
-    private int getScrollableHeight()
-    {
-        return Math.max(20 * lines.size(),height);
+    private int getScrollableHeight() {
+        return Math.max(20 * this.lines.size(), this.height);
     }
 
     @Override
-    public void onClick(int x, int y, int button)
-    {
+    public void onClick(final int x, final int y, final int button) {
         super.onClick(x, y, button);
-        
-        if(button == 0 && x >= scrollbarX && x < scrollbarX + scrollbarWidth && y >= scrollbarY && y < scrollbarY + scrollbarHeight) {
-        	isScrolling = true;
-        	previousScrollAmount = scrollAmount;
-        	clickY = y;
-        	return;
+
+        if (button == 0 && x >= this.scrollbarX && x < this.scrollbarX + this.scrollbarWidth && y >= this.scrollbarY && y < this.scrollbarY + this.scrollbarHeight) {
+            this.isScrolling = true;
+            this.previousScrollAmount = this.scrollAmount;
+            this.clickY = y;
         }
     }
-    
+
     @Override
-    public void mouseMovedOrUp(int x, int y, int button)
-    {
-    	super.mouseMovedOrUp(x, y, button);
-    	if(button == 0) {
-    		isScrolling = false;
-    		previousScrollAmount = 0.0f;
-    		clickY = 0;
-    	}
+    public void mouseMovedOrUp(final int x, final int y, final int button) {
+        super.mouseMovedOrUp(x, y, button);
+        if (button == 0) {
+            this.isScrolling = false;
+            this.previousScrollAmount = 0.0f;
+            this.clickY = 0;
+        }
     }
 
-    private void drawBackground(int x, int y)
-    {
-        Tessellator tessellator = Tessellator.instance;
+    private void drawBackground(final int x, final int y) {
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
         tessellator.setColorOpaque_I(0xA0A0A0);
-        tessellator.addVertex(x, y + height, 0.0D);
-        tessellator.addVertex(x + getWidth(), y + height, 0.0D);
-        tessellator.addVertex(x + getWidth(), y, 0.0D);
+        tessellator.addVertex(x, y + this.height, 0.0D);
+        tessellator.addVertex(x + this.getWidth(), y + this.height, 0.0D);
+        tessellator.addVertex(x + this.getWidth(), y, 0.0D);
         tessellator.addVertex(x, y, 0.0D);
         tessellator.draw();
         tessellator.startDrawingQuads();
         tessellator.setColorOpaque_I(0x000000);
-        tessellator.addVertex(x + 1, y + height - 1, 0.0D);
-        tessellator.addVertex(x + getWidth() - 1, y + height - 1, 0.0D);
-        tessellator.addVertex(x + getWidth() - 1, y + 1, 0.0D);
+        tessellator.addVertex(x + 1, y + this.height - 1, 0.0D);
+        tessellator.addVertex(x + this.getWidth() - 1, y + this.height - 1, 0.0D);
+        tessellator.addVertex(x + this.getWidth() - 1, y + 1, 0.0D);
         tessellator.addVertex(x + 1, y + 1, 0.0D);
         tessellator.draw();
     }
 
-    private void drawScrollbar(int x, int y, int mouseX, int mouseY)
-    {
-    	int scrollableHeight = getScrollableHeight();
-        int displayRegionHeight = height - 2;
-        float scrollbarScale = (float) displayRegionHeight / scrollableHeight;
-        
-    	scrollbarWidth = 6;
-        scrollbarHeight = (int) (scrollbarScale * displayRegionHeight);
-        
-        int minScrollbarY = 0;
-        int maxScrollbarY = displayRegionHeight - scrollbarHeight;
-        
-        int scrollbarDelta = maxScrollbarY - minScrollbarY;
-        
-        scrollbarY = y + 1 + (int) (scrollAmount * scrollbarDelta);
-        scrollbarX = x + getWidth() - 1 - 6;
-        
-        Tessellator t = Tessellator.instance;
+    private void drawScrollbar(final int x, final int y, final int mouseX, final int mouseY) {
+        final int scrollableHeight = this.getScrollableHeight();
+        final int displayRegionHeight = this.height - 2;
+        final float scrollbarScale = (float) displayRegionHeight / scrollableHeight;
+
+        this.scrollbarWidth = 6;
+        this.scrollbarHeight = (int) (scrollbarScale * displayRegionHeight);
+
+        final int minScrollbarY = 0;
+        final int maxScrollbarY = displayRegionHeight - this.scrollbarHeight;
+
+        final int scrollbarDelta = maxScrollbarY - minScrollbarY;
+
+        this.scrollbarY = y + 1 + (int) (this.scrollAmount * scrollbarDelta);
+        this.scrollbarX = x + this.getWidth() - 1 - 6;
+
+        final @NotNull Tessellator t = Tessellator.instance;
 
         t.startDrawingQuads();
         t.setColorRGBA_I(0x808080, 255);
-        t.drawRectangle(scrollbarX, scrollbarY, 6, scrollbarHeight);
+        t.drawRectangle(this.scrollbarX, this.scrollbarY, 6, this.scrollbarHeight);
         t.setColorRGBA_I(0xc0c0c0, 255);
-        t.drawRectangle(scrollbarX, scrollbarY, 5, scrollbarHeight - 1);
+        t.drawRectangle(this.scrollbarX, this.scrollbarY, 5, this.scrollbarHeight - 1);
         t.draw();
-        
-        if(isScrolling) {
-        	int delta = mouseY - clickY;
-        	float scrolledScreens = delta / (float) scrollbarHeight;
-        	float scrolledPixels = displayRegionHeight * scrolledScreens;
-        	float scrolledAmount = scrolledPixels / (float) (scrollableHeight - displayRegionHeight);
-        	
-        	scrollAmount = MathHelper.clamp(previousScrollAmount + scrolledAmount, 0.0f, 1.0f);
+
+        if (this.isScrolling) {
+            final int delta = mouseY - this.clickY;
+            final float scrolledScreens = delta / (float) this.scrollbarHeight;
+            final float scrolledPixels = displayRegionHeight * scrolledScreens;
+            final float scrolledAmount = scrolledPixels / (float) (scrollableHeight - displayRegionHeight);
+
+            this.scrollAmount = MathHelper.clamp(this.previousScrollAmount + scrolledAmount, 0.0f, 1.0f);
         }
-        
+
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
index 2dd4b7466..bacf4c74e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupBuilder.java
@@ -3,7 +3,8 @@ package net.minecraft.client.gui.popup;
 import it.unimi.dsi.fastutil.ints.IntIntPair;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.core.lang.I18n;
-import net.minecraft.core.util.collection.Pair;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 
@@ -11,51 +12,45 @@ import static net.minecraft.client.gui.popup.PopupScreen.VERTICAL_MARGIN;
 import static net.minecraft.client.gui.popup.PopupScreen.HORIZONTAL_MARGIN;
 import static net.minecraft.client.gui.popup.PopupScreen.COMPONENT_GAP;
 
-public class PopupBuilder
-{
-    private final Screen parent;
+public class PopupBuilder {
+    private final @Nullable Screen parent;
     private final int width;
-    private Integer statusCodeOnEsc = null;
-    private Integer statusCodeOnEnter = null;
-    private Integer statusCodeOnClickOut = null;
-    private final List<PopupComponent> components = new ArrayList<>();
-    private final Map<PopupComponent, String> componentKeyMap = new HashMap<>();
-    private final List<PopupCloseListener> onCloseListeners = new ArrayList<>();
-    private IntIntPair backgroundColor = null;
-
-    public PopupBuilder(Screen parent, int width)
-    {
+    private @Nullable Integer statusCodeOnEsc = null;
+    private @Nullable Integer statusCodeOnEnter = null;
+    private @Nullable Integer statusCodeOnClickOut = null;
+    private final @NotNull List<@NotNull PopupComponent> components = new ArrayList<>();
+    private final @NotNull Map<@NotNull PopupComponent, @NotNull String> componentKeyMap = new HashMap<>();
+    private final @NotNull List<@NotNull PopupCloseListener> onCloseListeners = new ArrayList<>();
+    private @Nullable IntIntPair backgroundColor = null;
+
+    public PopupBuilder(final @Nullable Screen parent, final int width) {
         this.parent = parent;
         this.width = width;
     }
 
-    public PopupScreen build()
-    {
-        PopupScreen popup = new PopupScreen(
-                parent,
-                width,
-                getHeight(),
-                statusCodeOnEsc,
-                statusCodeOnEnter,
-                statusCodeOnClickOut,
-                components,
-                componentKeyMap,
-                onCloseListeners,
-                backgroundColor
+    public PopupScreen build() {
+        final PopupScreen popup = new PopupScreen(
+            this.parent,
+            this.width,
+            this.getHeight(),
+            this.statusCodeOnEsc,
+            this.statusCodeOnEnter,
+            this.statusCodeOnClickOut,
+            this.components,
+            this.componentKeyMap,
+            this.onCloseListeners,
+            this.backgroundColor
         );
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             component.setParent(popup);
         }
         return popup;
     }
 
-    private int getHeight()
-    {
+    private int getHeight() {
         int accY = VERTICAL_MARGIN;
 
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             accY += component.getHeight() + COMPONENT_GAP;
         }
 
@@ -65,120 +60,104 @@ public class PopupBuilder
         return accY;
     }
 
-    public PopupBuilder closeOnEsc(int statusCode)
-    {
+    public @NotNull PopupBuilder closeOnEsc(final int statusCode) {
         this.statusCodeOnEsc = statusCode;
         return this;
     }
 
-    public PopupBuilder closeOnEnter(int statusCode)
-    {
+    public @NotNull PopupBuilder closeOnEnter(final int statusCode) {
         this.statusCodeOnEnter = statusCode;
         return this;
     }
 
-    public PopupBuilder closeOnClickOut(int statusCode)
-    {
+    public @NotNull PopupBuilder closeOnClickOut(final int statusCode) {
         this.statusCodeOnClickOut = statusCode;
         return this;
     }
 
-    public PopupBuilder withLabelLiteral(String text, int color)
-    {
-        PopupComponent component = new LabelComponent(width, text, color);
+    public @NotNull PopupBuilder withLabelLiteral(final @NotNull String text, final int color) {
+        final @NotNull PopupComponent component = new LabelComponent(this.width, text, color);
         this.components.add(component);
         return this;
     }
 
-    public PopupBuilder withLabelLiteral(String text)
-    {
-        return withLabelLiteral(text, 0xFFFFFFFF);
+    public @NotNull PopupBuilder withLabelLiteral(final @NotNull String text) {
+        return this.withLabelLiteral(text, 0xFFFFFFFF);
     }
 
-    public PopupBuilder withLabel(String translationKey, int color)
-    {
-        return withLabelLiteral(I18n.getInstance().translateKey(translationKey), color);
+    public @NotNull PopupBuilder withLabel(final @NotNull String translationKey, final int color) {
+        return this.withLabelLiteral(I18n.getInstance().translateKey(translationKey), color);
     }
 
-    public PopupBuilder withLabel(String translationKey)
-    {
-        return withLabel(translationKey, 0xFFFFFFFF);
+    public @NotNull PopupBuilder withLabel(final @NotNull String translationKey) {
+        return this.withLabel(translationKey, 0xFFFFFFFF);
     }
 
-    public PopupBuilder withTextField(String key, String defaultText)
-    {
-        PopupComponent component = new TextInputComponent(width - (HORIZONTAL_MARGIN * 2), defaultText, "");
+    public @NotNull PopupBuilder withTextField(final @NotNull String key, final @NotNull String defaultText) {
+        final @NotNull PopupComponent component = new TextInputComponent(this.width - (HORIZONTAL_MARGIN * 2), defaultText, "");
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withTextField(String key, String defaultText, String placeholderTranslationKey)
-    {
-        PopupComponent component = new TextInputComponent(width - (HORIZONTAL_MARGIN * 2), defaultText, I18n.getInstance().translateKey(placeholderTranslationKey));
+    public @NotNull PopupBuilder withTextField(final @NotNull String key, final @NotNull String defaultText, final @NotNull String placeholderTranslationKey) {
+        final @NotNull PopupComponent component = new TextInputComponent(this.width - (HORIZONTAL_MARGIN * 2), defaultText, I18n.getInstance().translateKey(placeholderTranslationKey));
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withButtonGroup(String key, String[] buttonTranslationKeys, int[] buttonStatusCodes)
-    {
-        String[] buttonLabels = new String[buttonTranslationKeys.length];
-        for (int i = 0; i < buttonTranslationKeys.length; i++)
-        {
+    public @NotNull PopupBuilder withButtonGroup(final @NotNull String key, final @NotNull String @NotNull [] buttonTranslationKeys, final int @NotNull [] buttonStatusCodes) {
+        final @NotNull String @NotNull [] buttonLabels = new String[buttonTranslationKeys.length];
+        for (int i = 0; i < buttonTranslationKeys.length; i++) {
             buttonLabels[i] = I18n.getInstance().translateKey(buttonTranslationKeys[i]);
         }
-        boolean[] enabled = new boolean[buttonTranslationKeys.length];
-        Arrays.fill(enabled,true);
-        PopupComponent component = new ButtonGroupComponent(width - (HORIZONTAL_MARGIN * 2), buttonLabels, buttonStatusCodes, enabled);
+        final boolean @NotNull [] enabled = new boolean[buttonTranslationKeys.length];
+        Arrays.fill(enabled, true);
+        final PopupComponent component = new ButtonGroupComponent(this.width - (HORIZONTAL_MARGIN * 2), buttonLabels, buttonStatusCodes, enabled);
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withButtonGroup(String key, String[] buttonTranslationKeys, int[] buttonStatusCodes, boolean[] enabled)
-    {
-        String[] buttonLabels = new String[buttonTranslationKeys.length];
-        for (int i = 0; i < buttonTranslationKeys.length; i++)
-        {
+    public PopupBuilder withButtonGroup(final @NotNull String key, final @NotNull String @NotNull [] buttonTranslationKeys, final int @NotNull [] buttonStatusCodes, final boolean @NotNull [] enabled) {
+        final @NotNull String @NotNull [] buttonLabels = new String[buttonTranslationKeys.length];
+        for (int i = 0; i < buttonTranslationKeys.length; i++) {
             buttonLabels[i] = I18n.getInstance().translateKey(buttonTranslationKeys[i]);
         }
-        PopupComponent component = new ButtonGroupComponent(width - (HORIZONTAL_MARGIN * 2), buttonLabels, buttonStatusCodes, enabled);
+        final @NotNull PopupComponent component = new ButtonGroupComponent(this.width - (HORIZONTAL_MARGIN * 2), buttonLabels, buttonStatusCodes, enabled);
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withList(String key, int height, String[] buttons, String[] buttonDescs, int selectedItem, boolean closeOnItemSelected)
-    {
-        PopupComponent component = new ListComponent(width - (HORIZONTAL_MARGIN * 2), height, buttons, buttonDescs, selectedItem, closeOnItemSelected);
+    public @NotNull PopupBuilder withList(final @NotNull String key, final int height, final @NotNull String @NotNull [] buttons, final @NotNull String @Nullable [] buttonDescs, final int selectedItem, final boolean closeOnItemSelected) {
+        final @NotNull PopupComponent component = new ListComponent(this.width - (HORIZONTAL_MARGIN * 2), height, buttons, buttonDescs, selectedItem, closeOnItemSelected);
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withMessageBox(String key, int height, String text, int chars)
-    {
-        PopupComponent component = new MessageBoxComponent(width - (HORIZONTAL_MARGIN * 2), height, text, chars);
+    public @NotNull PopupBuilder withMessageBox(final @NotNull String key, final int height, final @NotNull String text, final int chars) {
+        final @NotNull PopupComponent component = new MessageBoxComponent(this.width - (HORIZONTAL_MARGIN * 2), height, text, chars);
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withButton(String key, String labelTranslationKey, int defaultValue, String... valueTranslationKeys) {
-        PopupComponent component = new ButtonComponent(width - (HORIZONTAL_MARGIN * 2), labelTranslationKey, valueTranslationKeys, defaultValue);
+    public @NotNull PopupBuilder withButton(final @NotNull String key, final @NotNull String labelTranslationKey, final int defaultValue, final @NotNull String @NotNull ... valueTranslationKeys) {
+        final PopupComponent component = new ButtonComponent(this.width - (HORIZONTAL_MARGIN * 2), labelTranslationKey, valueTranslationKeys, defaultValue);
         this.components.add(component);
         this.componentKeyMap.put(component, key);
         return this;
     }
 
-    public PopupBuilder withBackgroundColor(int color, int color2){
-        this.backgroundColor = IntIntPair.of(color,color2);
+    public @NotNull PopupBuilder withBackgroundColor(final int color, final int color2) {
+        this.backgroundColor = IntIntPair.of(color, color2);
         return this;
     }
 
-    public PopupBuilder withOnCloseListener(PopupCloseListener listener)
-    {
+    public @NotNull PopupBuilder withOnCloseListener(final @NotNull PopupCloseListener listener) {
         this.onCloseListeners.add(listener);
         return this;
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupCloseListener.java b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupCloseListener.java
index 6103a514c..0a807bc9e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupCloseListener.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupCloseListener.java
@@ -1,8 +1,10 @@
 package net.minecraft.client.gui.popup;
 
+import org.jetbrains.annotations.NotNull;
+
 import java.util.Map;
 
 public interface PopupCloseListener
 {
-    void onClosed(int statusCode, Map<String, ?> results);
+    void onClosed(int statusCode, @NotNull Map<@NotNull String, ?> results);
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupComponent.java
index 01cf5ccc7..ae9a9caec 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupComponent.java
@@ -1,39 +1,40 @@
 package net.minecraft.client.gui.popup;
 
-public abstract class PopupComponent
-{
-    private PopupScreen parent = null;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class PopupComponent {
+    private @Nullable PopupScreen parent = null;
     private final int width;
 
-    public PopupComponent(int width)
-    {
+    public PopupComponent(final int width) {
         this.width = width;
     }
 
-    public void setParent(PopupScreen parent)
-    {
+    public void setParent(final @Nullable PopupScreen parent) {
         this.parent = parent;
     }
 
-    public PopupScreen getParent()
-    {
-        return parent;
+    public @Nullable PopupScreen getParent() {
+        return this.parent;
     }
 
-    public int getWidth()
-    {
-        return width;
+    public int getWidth() {
+        return this.width;
     }
 
     public abstract int getHeight();
 
-    public abstract void render(int x, int y, int mouseX, int mouseY);
+    public abstract void render(final int x, final int y, final int mouseX, final int mouseY);
+
+    public void onClick(final int x, final int y, final int button) {
+    }
 
-    public void onClick(int x, int y, int button) { }
-    
-    public void mouseMovedOrUp(int x, int y, int button) { }
+    public void mouseMovedOrUp(final int x, final int y, final int button) {
+    }
 
-    public void onKeyDown(int keyCode, char c) { }
+    public void onKeyDown(final int keyCode, final char c) {
+    }
 
-    public void tick() { }
+    public void tick() {
+    }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupScreen.java b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupScreen.java
index 37d3a95a2..c6af3e112 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/PopupScreen.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/PopupScreen.java
@@ -3,48 +3,47 @@ package net.minecraft.client.gui.popup;
 import it.unimi.dsi.fastutil.ints.IntIntPair;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.core.util.collection.Pair;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
 import java.util.*;
 
 public final class PopupScreen
-    extends Screen
-{
+    extends Screen {
     static final int HORIZONTAL_MARGIN = 8;
     static final int VERTICAL_MARGIN = 8;
     static final int COMPONENT_GAP = 4;
 
 
-    private final Screen parent;
+    private final @Nullable Screen parent;
     private final int popupWidth;
     private final int popupHeight;
 
-    private final Integer statusCodeOnEsc;
-    private final Integer statusCodeOnEnter;
-    private final Integer statusCodeOnClickOut;
-    private final List<PopupComponent> components;
-    private final Map<PopupComponent, String> componentKeyMap;
-    private final List<PopupCloseListener> onCloseListeners;
+    private final @Nullable Integer statusCodeOnEsc;
+    private final @Nullable Integer statusCodeOnEnter;
+    private final @Nullable Integer statusCodeOnClickOut;
+    private final @NotNull List<@NotNull PopupComponent> components;
+    private final @NotNull Map<@NotNull PopupComponent, @NotNull String> componentKeyMap;
+    private final @NotNull List<@NotNull PopupCloseListener> onCloseListeners;
 
-    private final IntIntPair backgroundColor;
+    private final @Nullable IntIntPair backgroundColor;
 
     private int statusCode = -1;
 
     PopupScreen(
-            Screen parent,
-            int width,
-            int height,
-            Integer statusCodeOnEsc,
-            Integer statusCodeOnEnter,
-            Integer statusCodeOnClickOut,
-            List<PopupComponent> components,
-            Map<PopupComponent, String> componentKeyMap,
-            List<PopupCloseListener> onCloseListeners,
-            IntIntPair backgroundColor
-    )
-    {
+        final @Nullable Screen parent,
+        final int width,
+        final int height,
+        final @Nullable Integer statusCodeOnEsc,
+        final @Nullable Integer statusCodeOnEnter,
+        final @Nullable Integer statusCodeOnClickOut,
+        final @NotNull List<@NotNull PopupComponent> components,
+        final @NotNull Map<@NotNull PopupComponent, @NotNull String> componentKeyMap,
+        final @NotNull List<@NotNull PopupCloseListener> onCloseListeners,
+        final @Nullable IntIntPair backgroundColor
+    ) {
         this.parent = parent;
         this.popupWidth = width;
         this.popupHeight = height;
@@ -57,124 +56,104 @@ public final class PopupScreen
         this.backgroundColor = backgroundColor;
     }
 
-    void close(int statusCode)
-    {
+    void close(final int statusCode) {
         this.statusCode = statusCode;
         this.removed();
-        mc.currentScreen = parent;
+        this.mc.currentScreen = this.parent;
     }
 
     @Override
-    public void tick()
-    {
+    public void tick() {
         super.tick();
 
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             component.tick();
         }
     }
 
     @Override
-    public void removed()
-    {
+    public void removed() {
         super.removed();
 
-        Map<String, Object> results = new HashMap<>();
-        for (Map.Entry<PopupComponent, String> entry : componentKeyMap.entrySet())
-        {
-            if (entry.getKey() instanceof InteractivePopupComponent<?>)
-            {
-                Object value = ((InteractivePopupComponent<?>) entry.getKey()).getOutput();
+        final @NotNull Map<@NotNull String, @NotNull Object> results = new HashMap<>();
+        for (final @NotNull Map.Entry<@NotNull PopupComponent, @NotNull String> entry : this.componentKeyMap.entrySet()) {
+            if (entry.getKey() instanceof InteractivePopupComponent<?>) {
+                final @NotNull Object value = ((InteractivePopupComponent<?>) entry.getKey()).getOutput();
                 results.put(entry.getValue(), value);
             }
         }
 
-        for (PopupCloseListener listener : onCloseListeners)
-        {
-            listener.onClosed(statusCode, results);
+        for (final @NotNull PopupCloseListener listener : this.onCloseListeners) {
+            listener.onClosed(this.statusCode, results);
         }
     }
 
     @Override
-    public void init()
-    {
-        if (parent.width != width || parent.height != height)
-        {
-            parent.width = width;
-            parent.height = height;
-            parent.buttons.clear();
-            parent.init();
+    public void init() {
+        if (this.parent != null && (this.parent.width != this.width || this.parent.height != this.height)) {
+            this.parent.width = this.width;
+            this.parent.height = this.height;
+            this.parent.buttons.clear();
+            this.parent.init();
         }
 
         super.init();
     }
 
     @Override
-    public void keyPressed(char eventCharacter, int eventKey, int mx, int my)
-    {
-        if (eventKey == Keyboard.KEY_ESCAPE && statusCodeOnEsc != null)
-        {
-            close(statusCodeOnEsc);
+    public void keyPressed(final char eventCharacter, final int eventKey, final int mx, final int my) {
+        if (eventKey == Keyboard.KEY_ESCAPE && this.statusCodeOnEsc != null) {
+            this.close(this.statusCodeOnEsc);
         }
-        if ((eventKey == Keyboard.KEY_RETURN || eventKey == Keyboard.KEY_NUMPADENTER) && statusCodeOnEnter != null)
-        {
-            close(statusCodeOnEnter);
+        if ((eventKey == Keyboard.KEY_RETURN || eventKey == Keyboard.KEY_NUMPADENTER) && this.statusCodeOnEnter != null) {
+            this.close(this.statusCodeOnEnter);
         }
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             component.onKeyDown(eventKey, eventCharacter);
         }
     }
 
     @Override
-    public void mouseClicked(int mx, int my, int buttonNum)
-    {
-        if (statusCodeOnClickOut != null)
-        {
-            int popupX = width / 2 - popupWidth / 2;
-            int popupY = height / 2 - popupHeight / 2;
-
-            if (mx < popupX || mx > popupX + popupWidth || my < popupY || my > popupY + popupHeight)
-            {
-                close(statusCodeOnClickOut);
+    public void mouseClicked(final int mx, final int my, final int buttonNum) {
+        if (this.statusCodeOnClickOut != null) {
+            final int popupX = this.width / 2 - this.popupWidth / 2;
+            final int popupY = this.height / 2 - this.popupHeight / 2;
+
+            if (mx < popupX || mx > popupX + this.popupWidth || my < popupY || my > popupY + this.popupHeight) {
+                this.close(this.statusCodeOnClickOut);
             }
         }
 
         super.mouseClicked(mx, my, buttonNum);
 
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             component.onClick(mx, my, buttonNum);
         }
     }
-    
+
     @Override
-    public void mouseReleased(int mx, int my, int buttonNum)
-    {
-    	super.mouseReleased(mx, my, buttonNum);
-    	
-    	for(PopupComponent component : components) {
-    		component.mouseMovedOrUp(mx, my, buttonNum);
-    	}
+    public void mouseReleased(final int mx, final int my, final int buttonNum) {
+        super.mouseReleased(mx, my, buttonNum);
+
+        for (final @NotNull PopupComponent component : this.components) {
+            component.mouseMovedOrUp(mx, my, buttonNum);
+        }
     }
 
     @Override
-    public void render(int mx, int my, float partialTick)
-    {
-        int popupX = width / 2 - popupWidth / 2;
-        int popupY = height / 2 - popupHeight / 2;
+    public void render(final int mx, final int my, final float partialTick) {
+        final int popupX = this.width / 2 - this.popupWidth / 2;
+        final int popupY = this.height / 2 - this.popupHeight / 2;
 
         if (this.parent != null) {
-            parent.render(-1, -1, partialTick);
+            this.parent.render(-1, -1, partialTick);
         }
 
-        drawPopupBackground();
+        this.drawPopupBackground();
 
         int accY = popupY + VERTICAL_MARGIN;
 
-        for (PopupComponent component : components)
-        {
+        for (final @NotNull PopupComponent component : this.components) {
             component.render(popupX + HORIZONTAL_MARGIN, accY, mx, my);
             accY += component.getHeight() + COMPONENT_GAP;
         }
@@ -182,34 +161,32 @@ public final class PopupScreen
         super.render(mx, my, partialTick);
     }
 
-    private void drawPopupBackground()
-    {
-        int popupX = width / 2 - popupWidth / 2;
-        int popupY = height / 2 - popupHeight / 2;
+    private void drawPopupBackground() {
+        final int popupX = this.width / 2 - this.popupWidth / 2;
+        final int popupY = this.height / 2 - this.popupHeight / 2;
 
         GL11.glDisable(GL11.GL_LIGHTING);
         GL11.glDisable(GL11.GL_FOG);
-        Tessellator tessellator = Tessellator.instance;
+        final @NotNull Tessellator tessellator = Tessellator.instance;
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
 
-        if(backgroundColor == null){
-            int color = mc.gameSettings.guiBackgroundColor.value.getARGB();
-            drawGradientRect(0, 0, width, height, color, color);
+        if (this.backgroundColor == null) {
+            final int color = this.mc.gameSettings.guiBackgroundColor.value.getARGB();
+            this.drawGradientRect(0, 0, this.width, this.height, color, color);
         } else {
-            drawGradientRect(0, 0, width, height, backgroundColor.leftInt(), backgroundColor.rightInt());
+            this.drawGradientRect(0, 0, this.width, this.height, this.backgroundColor.leftInt(), this.backgroundColor.rightInt());
         }
 
-
-        drawRectWidthHeight(popupX - 1, popupY - 1, popupWidth + 2, popupHeight + 2, 0xFFA0A0A0);
+        this.drawRectWidthHeight(popupX - 1, popupY - 1, this.popupWidth + 2, this.popupHeight + 2, 0xFFA0A0A0);
 
         GL11.glEnable(GL11.GL_TEXTURE_2D);
-        float f = 32F;
+        final float f = 32F;
         tessellator.startDrawingQuads();
-        mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
+        this.mc.textureManager.loadTexture("/assets/minecraft/textures/gui/background.png").bind();
         tessellator.setColorOpaque_I(0x404040);
-        tessellator.addVertexWithUV(popupX, popupY + popupHeight, 0.0D, 0.0D, (float)popupHeight / f);
-        tessellator.addVertexWithUV(popupX + popupWidth, popupY + popupHeight, 0.0D, (float)popupWidth / f, (float)popupHeight / f);
-        tessellator.addVertexWithUV(popupX + popupWidth, popupY, 0.0D, (float)popupWidth / f, 0);
+        tessellator.addVertexWithUV(popupX, popupY + this.popupHeight, 0.0D, 0.0D, (float) this.popupHeight / f);
+        tessellator.addVertexWithUV(popupX + this.popupWidth, popupY + this.popupHeight, 0.0D, (float) this.popupWidth / f, (float) this.popupHeight / f);
+        tessellator.addVertexWithUV(popupX + this.popupWidth, popupY, 0.0D, (float) this.popupWidth / f, 0);
         tessellator.addVertexWithUV(popupX, popupY, 0.0D, 0.0D, 0);
         tessellator.draw();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/popup/TextInputComponent.java b/game/client/src/main/java/net/minecraft/client/gui/popup/TextInputComponent.java
index 60a0a693c..c77703f99 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/popup/TextInputComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/popup/TextInputComponent.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui.popup;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.TextFieldElement;
+import org.jetbrains.annotations.NotNull;
 
 public class TextInputComponent
     extends InteractivePopupComponent<String>
@@ -22,7 +23,7 @@ public class TextInputComponent
     }
 
     @Override
-    public String getOutput()
+    public @NotNull String getOutput()
     {
         return textField.getText();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java
index 1fb8f6580..fcb5c878b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/BooleanGameRuleComponent.java
@@ -13,11 +13,10 @@ public class BooleanGameRuleComponent
     extends ButtonComponent
 {
     private @Nullable GameRuleCollection gameRuleCollection = null;
-    private final GameRuleBoolean gameRule;
-    private final SwitchElement button;
+    private final @NotNull GameRuleBoolean gameRule;
+    private final @NotNull SwitchElement button;
 
-    public BooleanGameRuleComponent(GameRuleBoolean gameRule)
-    {
+    public BooleanGameRuleComponent(final @NotNull GameRuleBoolean gameRule) {
         super(gameRule.getTranslationKey() + ".name", gameRule.getTranslationKey() + ".desc");
 
         this.gameRule = gameRule;
@@ -31,34 +30,36 @@ public class BooleanGameRuleComponent
 
     @Override
     public void resetValue() {
-        gameRuleCollection.setValue(this.gameRule, this.gameRule.getDefaultValue());
-        onChange();
+        assert this.gameRuleCollection != null;
+        this.gameRuleCollection.setValue(this.gameRule, this.gameRule.getDefaultValue());
+        this.onChange();
     }
 
     @Override
-    public void init(Minecraft mc){
-        onChange();
+    public void init(final @NotNull Minecraft mc){
+        this.onChange();
     }
 
     @Override
     public boolean isDefault() {
-        return gameRuleCollection.getValue(this.gameRule).equals(gameRule.getDefaultValue());
+        assert this.gameRuleCollection != null;
+        return this.gameRuleCollection.getValue(this.gameRule).equals(this.gameRule.getDefaultValue());
     }
 
     @Override
-    protected void buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY)
-    {
-        gameRuleCollection.setValue(this.gameRule, !this.gameRuleCollection.getValue(this.gameRule));
-        onChange();
+    protected void buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        assert this.gameRuleCollection != null;
+        this.gameRuleCollection.setValue(this.gameRule, !this.gameRuleCollection.getValue(this.gameRule));
+        this.onChange();
     }
 
     protected void onChange() {
+        assert this.gameRuleCollection != null;
         this.button.setOn(this.gameRuleCollection.getValue(this.gameRule));
     }
 
     @Override
-    protected void renderButton(int x, int y, int relativeButtonX, int relativeButtonY, int buttonWidth, int buttonHeight, int relativeMouseX, int relativeMouseY)
-    {
+    protected void renderButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
         super.renderButton(x, y, relativeButtonX, relativeButtonY, buttonWidth, buttonHeight, relativeMouseX, relativeMouseY);
 
         this.button.xPosition = x + relativeButtonX;
@@ -68,7 +69,7 @@ public class BooleanGameRuleComponent
 
         this.button.drawButton(mc, x + relativeMouseX, y + relativeMouseY);
 
-        if (relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
+        if (mc.currentScreen != null && relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
             mc.currentScreen.setDesiredCursor(CursorShape.HAND);
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
index 654639ba5..daf0493d4 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ButtonComponent.java
@@ -15,25 +15,21 @@ import static org.lwjgl.opengl.GL11.*;
 import static org.lwjgl.opengl.GL11.GL_BLEND;
 
 public abstract class ButtonComponent
-    implements PageComponent
-{
-    protected static final Minecraft mc = Minecraft.getMinecraft();
+    implements PageComponent {
+    protected static final @NotNull Minecraft mc = Minecraft.getMinecraft();
     protected static final int COMPONENT_SPACING = 2;
     private static final int BUTTON_WIDTH = 100;
 
     private final @NotNull String translationKey;
     private final @Nullable String tooltipTranslationKey;
 
-    protected final ButtonElement resetButton;
+    protected final @NotNull ButtonElement resetButton;
 
-    private boolean hovered = false;
-
-    public ButtonComponent(@NotNull String translationKey, @Nullable String tooltipTranslationKey)
-    {
+    public ButtonComponent(final @NotNull String translationKey, final @Nullable String tooltipTranslationKey) {
         this.translationKey = translationKey;
         this.tooltipTranslationKey = tooltipTranslationKey;
         this.resetButton = new ButtonElement(0, 0, 0, 20, 20, "")
-                .setTextures("minecraft:gui/misc/icon_reset", "minecraft:gui/misc/icon_reset_highlighted", "minecraft:gui/misc/icon_reset");
+            .setTextures("minecraft:gui/misc/icon_reset", "minecraft:gui/misc/icon_reset_highlighted", "minecraft:gui/misc/icon_reset");
     }
 
     public abstract void resetValue();
@@ -41,78 +37,71 @@ public abstract class ButtonComponent
     public abstract boolean isDefault();
 
     @Override
-    public int getHeight()
-    {
+    public int getHeight() {
         return COMPONENT_SPACING + 20 + COMPONENT_SPACING;
     }
 
     @Override
-    public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY)
-    {
-        String translated = I18n.getInstance().translateKey(translationKey);
+    public void render(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        final @NotNull String translated = I18n.getInstance().translateKey(this.translationKey);
         int textColor = 0xFFFFFFFF;
-        if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= getHeight() - COMPONENT_SPACING) {
+        if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= this.getHeight() - COMPONENT_SPACING) {
             textColor = 0xFFFFFFA0;
         }
 
-        if (relativeMouseX >= 0 && relativeMouseX <= width - BUTTON_WIDTH && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= getHeight() - COMPONENT_SPACING) {
-            this.hovered = true;
-        } else {
-            this.hovered = false;
-        }
-
-        mc.font.render(Tessellator.instance, translated, x, y + (getHeight() / 2) - 4).setShadow().setColor(textColor).call();
-        resetButton.enabled = !isDefault();
-        renderButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, BUTTON_WIDTH, 20, relativeMouseX, relativeMouseY);
-        int stringWidth = mc.font.stringWidth(translated);
+        mc.font.render(Tessellator.instance, translated, x, y + (this.getHeight() / 2) - 4).setShadow().setColor(textColor).call();
+        this.resetButton.enabled = !this.isDefault();
+        this.renderButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, BUTTON_WIDTH, 20, relativeMouseX, relativeMouseY);
+        final int stringWidth = mc.font.stringWidth(translated);
         int lineMaxX = x + width - BUTTON_WIDTH - 8;
-        if (resetButton.enabled) lineMaxX -= 20;
-        drawRect(x + stringWidth + 8, y + getHeight() / 2, lineMaxX, y + getHeight() / 2 + 1, 0x5F7F7F7F);
+        if (this.resetButton.enabled) lineMaxX -= 20;
+        this.drawRect(x + stringWidth + 8, y + this.getHeight() / 2, lineMaxX, y + this.getHeight() / 2 + 1, 0x5F7F7F7F);
     }
 
     @Override
-    public void onMouseClick(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY)
-    {
+    public void onMouseClick(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
         if (relativeMouseX >= width - BUTTON_WIDTH && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + 20) {
             mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
-            buttonClicked(mouseButton, x, y, width, getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
-        } else if (resetButton.enabled && relativeMouseX >= width - BUTTON_WIDTH - 20 && relativeMouseX <= width - BUTTON_WIDTH && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + 20) {
+            this.buttonClicked(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+        } else if (this.resetButton.enabled && relativeMouseX >= width - BUTTON_WIDTH - 20 && relativeMouseX <= width - BUTTON_WIDTH && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= COMPONENT_SPACING + 20) {
             mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
-            resetValue();
+            this.resetValue();
         }
     }
 
     @Override
-    public void onMouseMove(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-        buttonDragged(x, y, width, getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+    public void onMouseMove(final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        this.buttonDragged(x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
     }
 
     @Override
-    public void onMouseRelease(int mouseButton, int x, int y, int width, int relativeMouseX, int relativeMouseY) {
-        buttonReleased(mouseButton, x, y, width, getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
+    public void onMouseRelease(final int mouseButton, final int x, final int y, final int width, final int relativeMouseX, final int relativeMouseY) {
+        this.buttonReleased(mouseButton, x, y, width, this.getHeight(), relativeMouseX - (width - BUTTON_WIDTH), relativeMouseY - COMPONENT_SPACING);
     }
 
     protected abstract void buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY);
 
-    protected void buttonDragged(int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) { }
+    protected void buttonDragged(final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+    }
 
-    protected void buttonReleased(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) { }
+    protected void buttonReleased(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+    }
 
     @Override
-    public void onKeyPress(int keyCode, char character) { }
+    public void onKeyPress(final int keyCode, final char character) {
+    }
 
     @Override
-    public boolean matchesSearchTerm(String term)
-    {
-        return I18n.getInstance().translateKey(translationKey).toLowerCase().contains(term.toLowerCase());
+    public boolean matchesSearchTerm(final @NotNull String term) {
+        return I18n.getInstance().translateKey(this.translationKey).toLowerCase().contains(term.toLowerCase());
     }
 
-    protected void renderButton(int x, int y, int relativeButtonX, int relativeButtonY, int buttonWidth, int buttonHeight, int relativeMouseX, int relativeMouseY) {
-        if (resetButton.enabled) {
-            resetButton.xPosition = x + relativeButtonX - 20;
-            resetButton.yPosition = y + relativeButtonY;
+    protected void renderButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
+        if (this.resetButton.enabled) {
+            this.resetButton.xPosition = x + relativeButtonX - 20;
+            this.resetButton.yPosition = y + relativeButtonY;
 
-            resetButton.drawButton(mc, x + relativeMouseX, y + relativeMouseY);
+            this.resetButton.drawButton(mc, x + relativeMouseX, y + relativeMouseY);
 
             if (relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
                 mc.currentScreen.setDesiredCursor(CursorShape.HAND);
@@ -120,9 +109,8 @@ public abstract class ButtonComponent
         }
     }
 
-    protected void drawRect(int minX, int minY, int maxX, int maxY, int argb)
-    {
-        Tessellator tessellator = Tessellator.instance;
+    protected void drawRect(final int minX, final int minY, final int maxX, final int maxY, final int argb) {
+        final Tessellator tessellator = Tessellator.instance;
         GL11.glEnable(GL_BLEND);
         GL11.glDisable(GL_TEXTURE_2D);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java
new file mode 100644
index 000000000..153aae41b
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/IntegerGameRuleComponent.java
@@ -0,0 +1,50 @@
+package net.minecraft.client.gui.worldsettings;
+
+import net.minecraft.client.gui.SwitchElement;
+import net.minecraft.client.gui.TextFieldElement;
+import net.minecraft.core.data.gamerule.GameRuleBoolean;
+import net.minecraft.core.data.gamerule.GameRuleCollection;
+import net.minecraft.core.data.gamerule.GameRuleInteger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class IntegerGameRuleComponent
+    extends ButtonComponent {
+    private @Nullable GameRuleCollection gameRuleCollection = null;
+    private final @NotNull GameRuleInteger gameRule;
+    private final @NotNull TextFieldElement textField;
+
+    public IntegerGameRuleComponent(final @NotNull GameRuleInteger gameRule) {
+        super(gameRule.getTranslationKey() + ".name", gameRule.getTranslationKey() + ".desc");
+
+        this.gameRule = gameRule;
+        this.textField = new TextFieldElement(mc.currentScreen, mc.font, 0, 0, 150, 20, this.gameRule.getDefaultValue().toString(), null);
+    }
+
+    public void setGameRuleCollection(final @NotNull GameRuleCollection collection) {
+        this.gameRuleCollection = collection;
+    }
+
+    @Override
+    public void resetValue() {
+        assert this.gameRuleCollection != null;
+        this.gameRuleCollection.setValue(this.gameRule, this.gameRule.getDefaultValue());
+        this.onChange();
+    }
+
+    @Override
+    public boolean isDefault() {
+        assert this.gameRuleCollection != null;
+        return this.gameRuleCollection.getValue(this.gameRule).equals(this.gameRule.getDefaultValue());
+    }
+
+    @Override
+    protected void buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+
+    }
+
+    protected void onChange() {
+        assert this.gameRuleCollection != null;
+        this.textField.setText(this.gameRuleCollection.getValue(this.gameRule).toString());
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
index 751a62ca9..87c7514f6 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/ScreenWorldSettings.java
@@ -11,6 +11,7 @@ import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.world.settings.WorldConfiguration;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 
@@ -33,20 +34,20 @@ public class ScreenWorldSettings
 
     private final @NotNull WorldConfiguration worldConfiguration;
 
-    public ScreenWorldSettings(Screen parent, final @NotNull WorldConfiguration worldConfiguration) {
+    public ScreenWorldSettings(final @Nullable Screen parent, final @NotNull WorldConfiguration worldConfiguration) {
         super(parent, CREATE_WORLD_PAGES, PAGE_GAME_RULES, "gui.world_settings.label.title", new String[] { "gui.world_settings.button.done" });
 
         this.worldConfiguration = worldConfiguration;
 
         final List<PageComponent> gameRulesPageComponents = PAGE_GAME_RULES.getComponents();
-        for (PageComponent component : gameRulesPageComponents) {
+        for (final @NotNull  PageComponent component : gameRulesPageComponents) {
             if (component instanceof BooleanGameRuleComponent) {
                 ((BooleanGameRuleComponent) component).setGameRuleCollection(worldConfiguration.getGameRuleCollection());
             }
         }
 
         final List<PageComponent> worldSettingsPageComponents = PAGE_WORLD_SETTINGS.getComponents();
-        for (PageComponent component : worldSettingsPageComponents) {
+        for (final @NotNull PageComponent component : worldSettingsPageComponents) {
             if (component instanceof WorldTypeButtonComponent) {
                 ((WorldTypeButtonComponent) component).setWorldConfiguration(worldConfiguration);
             }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/WorldTypeButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/WorldTypeButtonComponent.java
index b41282c39..b3fa127aa 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/worldsettings/WorldTypeButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/worldsettings/WorldTypeButtonComponent.java
@@ -1,7 +1,6 @@
 package net.minecraft.client.gui.worldsettings;
 
 import net.minecraft.client.gui.ButtonElement;
-import net.minecraft.client.gui.SwitchElement;
 import net.minecraft.client.gui.popup.PopupBuilder;
 import net.minecraft.client.gui.popup.PopupScreen;
 import net.minecraft.client.render.window.CursorShape;
@@ -14,11 +13,12 @@ import net.minecraft.core.world.type.WorldTypeGroups;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.Objects;
+
 public class WorldTypeButtonComponent
-    extends ButtonComponent
-{
+    extends ButtonComponent {
     private @Nullable WorldConfiguration worldConfiguration = null;
-    private final ButtonElement button;
+    private final @NotNull ButtonElement button;
 
     public WorldTypeButtonComponent(final @NotNull String translationKey, final @Nullable String tooltipTranslationKey) {
         super(translationKey, tooltipTranslationKey);
@@ -33,43 +33,43 @@ public class WorldTypeButtonComponent
 
     @Override
     public void resetValue() {
-        this.worldConfiguration.setWorldTypeGroup(WorldTypeGroups.DEFAULT);
+        Objects.requireNonNull(this.worldConfiguration).setWorldTypeGroup(WorldTypeGroups.DEFAULT);
         this.button.displayString = I18n.getInstance().translateKey(this.worldConfiguration.getWorldTypeGroup().get(Dimension.OVERWORLD).getLanguageKey() + ".name");
     }
 
     @Override
     public boolean isDefault() {
-        return this.worldConfiguration.getWorldTypeGroup() == WorldTypeGroups.DEFAULT;
+        return Objects.requireNonNull(this.worldConfiguration).getWorldTypeGroup() == WorldTypeGroups.DEFAULT;
     }
 
     @Override
-    protected void buttonClicked(int mouseButton, int x, int y, int width, int height, int relativeMouseX, int relativeMouseY) {
-        I18n i18n = I18n.getInstance();
-        String[] keys = new String[WorldTypeGroups.GROUPS.size()];
-        String[] descs = new String[WorldTypeGroups.GROUPS.size()];
+    protected void buttonClicked(final int mouseButton, final int x, final int y, final int width, final int height, final int relativeMouseX, final int relativeMouseY) {
+        final I18n i18n = I18n.getInstance();
+        final @NotNull String @NotNull [] keys = new String[WorldTypeGroups.GROUPS.size()];
+        final @NotNull String @NotNull [] descs = new String[WorldTypeGroups.GROUPS.size()];
         for (int i = 0; i < keys.length; i++) {
             keys[i] = i18n.translateKey(WorldTypeGroups.GROUPS.get(i).get(Dimension.OVERWORLD).getLanguageKey() + ".name");
             descs[i] = i18n.translateKey(WorldTypeGroups.GROUPS.get(i).get(Dimension.OVERWORLD).getLanguageKey() + ".desc") + "\n" +
-                    TextFormatting.GRAY + Registries.WORLD_TYPES.getKey(WorldTypeGroups.GROUPS.get(i).get(Dimension.OVERWORLD));
+                TextFormatting.GRAY + Registries.WORLD_TYPES.getKey(WorldTypeGroups.GROUPS.get(i).get(Dimension.OVERWORLD));
         }
 
-        PopupScreen popup = new PopupBuilder(mc.currentScreen, 150)
-                .closeOnEsc(0)
-                .closeOnClickOut(0)
-                .withLabel("gui.world_settings.label.select_world_type")
-                .withList("worldTypeList", 140, keys, descs, WorldTypeGroups.GROUPS.indexOf(this.worldConfiguration.getWorldTypeGroup()), true)
-                .withOnCloseListener((statusCode, results) -> {
-                    if (statusCode == 1) {
-                        this.worldConfiguration.setWorldTypeGroup(WorldTypeGroups.GROUPS.get((Integer) results.get("worldTypeList")));
-                        this.button.displayString = I18n.getInstance().translateKey(this.worldConfiguration.getWorldTypeGroup().get(Dimension.OVERWORLD).getLanguageKey() + ".name");
-                    }
-                })
-                .build();
+        final PopupScreen popup = new PopupBuilder(Objects.requireNonNull(mc.currentScreen), 150)
+            .closeOnEsc(0)
+            .closeOnClickOut(0)
+            .withLabel("gui.world_settings.label.select_world_type")
+            .withList("worldTypeList", 140, keys, descs, WorldTypeGroups.GROUPS.indexOf(Objects.requireNonNull(this.worldConfiguration).getWorldTypeGroup()), true)
+            .withOnCloseListener((statusCode, results) -> {
+                if (statusCode == 1) {
+                    this.worldConfiguration.setWorldTypeGroup(Objects.requireNonNull(WorldTypeGroups.GROUPS.get((Integer) results.get("worldTypeList"))));
+                    this.button.displayString = I18n.getInstance().translateKey(this.worldConfiguration.getWorldTypeGroup().get(Dimension.OVERWORLD).getLanguageKey() + ".name");
+                }
+            })
+            .build();
         mc.displayScreen(popup);
     }
 
     @Override
-    protected void renderButton(int x, int y, int relativeButtonX, int relativeButtonY, int buttonWidth, int buttonHeight, int relativeMouseX, int relativeMouseY) {
+    protected void renderButton(final int x, final int y, final int relativeButtonX, final int relativeButtonY, final int buttonWidth, final int buttonHeight, final int relativeMouseX, final int relativeMouseY) {
         super.renderButton(x, y, relativeButtonX, relativeButtonY, buttonWidth, buttonHeight, relativeMouseX, relativeMouseY);
 
         this.button.xPosition = x + relativeButtonX;
@@ -79,7 +79,7 @@ public class WorldTypeButtonComponent
 
         this.button.drawButton(mc, x + relativeMouseX, y + relativeMouseY);
 
-        if (relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
+        if (mc.currentScreen != null && relativeMouseX >= relativeButtonX && relativeMouseX < relativeButtonX + buttonWidth && relativeMouseY >= relativeButtonY && relativeButtonY < relativeButtonY + buttonHeight) {
             mc.currentScreen.setDesiredCursor(CursorShape.HAND);
         }
     }
diff --git a/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInput.java b/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInput.java
index 02a035d99..85a4a8930 100644
--- a/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInput.java
+++ b/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInput.java
@@ -6,6 +6,7 @@ import net.minecraft.client.gui.container.ScreenContainerAbstract;
 import net.minecraft.client.input.glfw.GlfwGamepad;
 import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.core.util.helper.Time;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.glfw.GLFW;
 
 public class ControllerInput {
@@ -17,24 +18,24 @@ public class ControllerInput {
     public Joystick joyLeft;
     public Joystick joyRight;
 
-    public Button buttonA;
-    public Button buttonB;
-    public Button buttonX;
-    public Button buttonY;
+    public @NotNull Button buttonA;
+    public @NotNull Button buttonB;
+    public @NotNull Button buttonX;
+    public @NotNull Button buttonY;
 
-    public Button buttonLeftTrigger;
-    public Button buttonRightTrigger;
+    public @NotNull Button buttonLeftTrigger;
+    public @NotNull Button buttonRightTrigger;
 
-    public Button buttonBack;
-    public Button buttonStart;
+    public @NotNull Button buttonBack;
+    public @NotNull Button buttonStart;
 
-    public Button buttonLeftShoulder;
-    public Button buttonRightShoulder;
+    public @NotNull Button buttonLeftShoulder;
+    public @NotNull Button buttonRightShoulder;
 
-    public DigitalPad digitalPad;
+    public @NotNull DigitalPad digitalPad;
 
-    public Button[] buttons;
-    public Joystick[] joysticks;
+    public @NotNull Button @NotNull [] buttons;
+    public @NotNull Joystick @NotNull [] joysticks;
 
     public boolean hideCursor = false;
     public boolean lockCursor = false;
@@ -53,18 +54,6 @@ public class ControllerInput {
 
         this.type = ControllerType.fromController(controller);
 
-        setup();
-    }
-
-    public String getGUID() {
-        return controller.getGuid();
-    }
-
-    public ControllerType getType() {
-        return type;
-    }
-
-    public void setup() {
         IButtonListener defaultButtonListener = controller::isButtonPressed;
         IJoystickListener defaultJoystickListener = controller::getAxisValue;
 
@@ -115,6 +104,14 @@ public class ControllerInput {
         joysticks = ReflectUtils.getAllObjects(ControllerInput.class, Joystick.class, this);
     }
 
+    public String getGUID() {
+        return controller.getGuid();
+    }
+
+    public ControllerType getType() {
+        return type;
+    }
+
     public void moveCursor() {
         if (lockCursor) return;
         double speed = 300 * Time.delta * (minecraft.gameSettings.controllerMenuSensitivity.value + 0.5f);
diff --git a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
index 9d8490f35..5cb6b3174 100644
--- a/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/game/client/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.option;
 
+import static net.minecraft.core.util.Util.emptyStringIfNull;
 import static org.lwjgl.input.Keyboard.*;
 
 import java.io.BufferedReader;
@@ -33,6 +34,7 @@ import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Color;
 import net.minecraft.core.util.helper.ITranslatable;
 
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 public class GameSettings {
@@ -42,238 +44,239 @@ public class GameSettings {
 	public final Minecraft mc;
 	private final File optionsFile;
 
-	public OptionInteger windowWidth = new OptionInteger(this, "windowWidth", 854);
-	public OptionInteger windowHeight = new OptionInteger(this, "windowHeight", 480);
+	public @NotNull OptionInteger windowWidth = new OptionInteger(this, "windowWidth", 854);
+	public @NotNull OptionInteger windowHeight = new OptionInteger(this, "windowHeight", 480);
 	
-	public OptionVolume masterVolume = new OptionVolume(this, "sound.master", 1.0f, SoundCategory.GUI_SOUNDS);
-	public OptionVolume musicVolume = new OptionVolume(this, "sound.music", 1.0f, SoundCategory.MUSIC);
-	public OptionVolume worldSoundsVolume = new OptionVolume(this, "sound.world", 1.0f, SoundCategory.WORLD_SOUNDS);
-	public OptionVolume entitySoundsVolume = new OptionVolume(this, "sound.entity", 1.0f, SoundCategory.ENTITY_SOUNDS);
-	public OptionVolume caveSoundsVolume = new OptionVolume(this, "sound.cave", 1.0f, SoundCategory.CAVE_SOUNDS);
-	public OptionVolume guiSoundsVolume = new OptionVolume(this, "sound.gui", 1.0f, SoundCategory.GUI_SOUNDS);
-	public OptionVolume weatherSoundsVolume = new OptionVolume(this, "sound.weather", 1.0f, SoundCategory.WEATHER_SOUNDS);
+	public @NotNull OptionVolume masterVolume = new OptionVolume(this, "sound.master", 1.0f, SoundCategory.GUI_SOUNDS);
+	public @NotNull OptionVolume musicVolume = new OptionVolume(this, "sound.music", 1.0f, SoundCategory.MUSIC);
+	public @NotNull OptionVolume worldSoundsVolume = new OptionVolume(this, "sound.world", 1.0f, SoundCategory.WORLD_SOUNDS);
+	public @NotNull OptionVolume entitySoundsVolume = new OptionVolume(this, "sound.entity", 1.0f, SoundCategory.ENTITY_SOUNDS);
+	public @NotNull OptionVolume caveSoundsVolume = new OptionVolume(this, "sound.cave", 1.0f, SoundCategory.CAVE_SOUNDS);
+	public @NotNull OptionVolume guiSoundsVolume = new OptionVolume(this, "sound.gui", 1.0f, SoundCategory.GUI_SOUNDS);
+	public @NotNull OptionVolume weatherSoundsVolume = new OptionVolume(this, "sound.weather", 1.0f, SoundCategory.WEATHER_SOUNDS);
 	
-	public OptionFloat FoV = new OptionFloat(this, "fov", 0.40140846f);
-	public OptionFloat mouseSensitivity = new OptionFloat(this, "mouseSensitivity", 0.5f);
-	public OptionFloat screenPadding = new OptionFloat(this, "screenPadding", 0.0f);
-	public OptionFloat gamma = new OptionFloat(this, "gamma", 0.5f);
-	public OptionFloat brightness = new OptionFloat(this, "brightness", 0.5f);
-
-	public OptionFloat fxaa = new OptionFloat(this, "fxaa", 0.0f);
-	public OptionFloat controllerSensitivity = new OptionFloat(this, "controllerSensitivity", 0.5f);
-	public OptionFloat controllerMenuSensitivity = new OptionFloat(this, "controllerMenuSensitivity", 0.5f);
-	public OptionFloat controllerDeadzoneLeft = new OptionFloat(this, "controllerDeadzoneL", 0.25f);
-	public OptionFloat controllerDeadzoneRight = new OptionFloat(this, "controllerDeadzoneR", 0.25f);
-	public OptionFloat blockOutlineWidth = new OptionFloat(this, "blockOutlineWidth", 0.25f);
+	public @NotNull OptionFloat FoV = new OptionFloat(this, "fov", 0.40140846f);
+	public @NotNull OptionFloat mouseSensitivity = new OptionFloat(this, "mouseSensitivity", 0.5f);
+	public @NotNull OptionFloat screenPadding = new OptionFloat(this, "screenPadding", 0.0f);
+	public @NotNull OptionFloat gamma = new OptionFloat(this, "gamma", 0.5f);
+	public @NotNull OptionFloat brightness = new OptionFloat(this, "brightness", 0.5f);
+
+	public @NotNull OptionFloat fxaa = new OptionFloat(this, "fxaa", 0.0f);
+	public @NotNull OptionFloat controllerSensitivity = new OptionFloat(this, "controllerSensitivity", 0.5f);
+	public @NotNull OptionFloat controllerMenuSensitivity = new OptionFloat(this, "controllerMenuSensitivity", 0.5f);
+	public @NotNull OptionFloat controllerDeadzoneLeft = new OptionFloat(this, "controllerDeadzoneL", 0.25f);
+	public @NotNull OptionFloat controllerDeadzoneRight = new OptionFloat(this, "controllerDeadzoneR", 0.25f);
+	public @NotNull OptionFloat blockOutlineWidth = new OptionFloat(this, "blockOutlineWidth", 0.25f);
 	
-	public OptionFloat flightSpeed = new OptionFloat(this, "flightSpeed", 0.5f);
-	public OptionFloat flightSmoothness = new OptionFloat(this, "flightSmoothness", 0.5f);
-
-	public OptionBoolean invertMouse = new OptionBoolean(this, "invertYMouse", false);
-	public OptionBoolean rawMouseInput = new OptionBoolean(this, "rawMouseInput", false);
-	public OptionBoolean viewBobbing = new OptionBoolean(this, "bobView", true);
-	public OptionBoolean advancedOpenGL = new OptionBoolean(this, "advancedOpengl", false);
-	public OptionRange fancyGraphics = new OptionRange(this, "fancyGraphics", 1, 2);
-	public OptionBoolean treeShadows = new OptionBoolean(this, "treeShadows", true);
-	public OptionBoolean connectedGlass = new OptionBoolean(this, "connectedGlass", false);
-	public OptionBoolean ambientOcclusion = new OptionBoolean(this, "ambientOcclusion", true);
-	public OptionBoolean items3D = new OptionBoolean(this, "3Ditems", false);
-	public OptionBoolean smoothCamera = new OptionBoolean(this, "smoothCamera", false);
-	public OptionBoolean lockCamera = new OptionBoolean(this, "lockCamera", false);
-	public OptionBoolean biomeWater = new OptionBoolean(this, "biomeWater", true);
-	public OptionBoolean vignette = new OptionBoolean(this, "vignette", true);
-	public OptionBoolean showPlayerList = new OptionBoolean(this, "showPlayerList", false);
-	public OptionBoolean slimeParticles = new OptionBoolean(this, "slimeParticles", true);
-	public OptionBoolean disableShaders = new OptionBoolean(this, "disableShaders", false);
-	public OptionString shaderOverride = new OptionString(this, "shaderOverride", "");
-	public OptionBoolean autoHit = new OptionBoolean(this, "autoHit", true);
-	public OptionBoolean easyBridge = new OptionBoolean(this, "easyBridge", true);
-	public OptionBoolean foodHealthRegenOverlay = new OptionBoolean(this, "foodHealthRegenOverlay", true);
-	public OptionBoolean fpsInOverlay = new OptionBoolean(this, "fpsInOverlay", false);
-	public OptionBoolean versionInOverlay = new OptionBoolean(this, "versionInOverlay", false);
-	public OptionBoolean controllerSwapShoulderButtons = new OptionBoolean(this, "controllerSwapShoulderButtons", false);
-	public OptionBoolean controllerSwapAB = new OptionBoolean(this, "controllerSwapAB", false);
-	public OptionBoolean controllerSwapXY = new OptionBoolean(this, "controllerSwapXY", false);
-	public OptionBoolean clouds = new OptionBoolean(this, "clouds", true);
-	public OptionFloat cloudHeight = new OptionFloat(this, "cloudHeight", 0f);
-	public OptionBoolean armorDurabilityOverlay = new OptionBoolean(this, "armorDurabilityOverlay", false);
-	public OptionBoolean armorProtectionOverlay = new OptionBoolean(this, "armorProtectionOverlay", true);
-	public OptionBoolean heldItemCountOverlay = new OptionBoolean(this, "heldItemCountOverlay", false);
-	public OptionBoolean pauseOnLostFocus = new OptionBoolean(this, "pauseOnLostFocus", true);
-	public OptionBoolean showDebugScreen = new OptionBoolean(this, "showDebugScreen", false);
-	public OptionBoolean showFrameTimes = new OptionBoolean(this, "showFrameTimes", false);
-	public OptionBoolean showItemDebugInfo = new OptionBoolean(this, "showItemDebugInfo", false);
-	public OptionBoolean showChunkBorders = new OptionBoolean(this, "showChunkBorders", false);
-	public OptionBoolean showCollisionBoxes = new OptionBoolean(this, "showCollisionBoxes", false);
-	public OptionBoolean swapCraftingButtons = new OptionBoolean(this, "swapCraftingButtons", false);
-	public OptionBoolean forceOnscreenKeyboard = new OptionBoolean(this, "forceOnscreenKeyboard", false);
-	public OptionEnum<PlacementMode> placementMode = new OptionEnum<>(this, "placementMode", PlacementMode.class, PlacementMode.DEFAULT).setIsSlider(false);
-	public OptionBoolean discordRichPresence = new OptionBoolean(this, "discordRichPresence", false);
-	public OptionImmersiveMode immersiveMode = new OptionImmersiveMode(this);
-	public OptionColor guiBackgroundColor = new OptionColor(this, "guiBackgroundColor", new Color().setARGB(0xc0101010));
-	public OptionEnum<Difficulty> difficulty = new OptionEnum<>(this, "difficulty", Difficulty.class, Difficulty.NORMAL); // Stub for local difficulty setting
-	public OptionInteger thirdPersonView = new OptionInteger(this, "thirdPersonView", 0);
-	public OptionRange renderDistance = new OptionRange(this, "renderDistance", 12, 2, 32);
-	public OptionBoolean enableVsync = new OptionBoolean(this, "enableVsync", false);
-	public OptionEnum<ChatVisibility> chatVisibility = new OptionEnum<>(this, "chatVisibility", ChatVisibility.class, ChatVisibility.SHOW_ALL);
-	public OptionRange customFpsLimit = new OptionRange(this,"customFpsLimit",0,241);
-	public OptionInteger guiScale = new OptionInteger(this, "guiScale", 0);
-	public OptionInteger overlayMode = new OptionInteger(this, "overlayMode", 0);
-	public OptionInteger rotationOverlayMode = new OptionInteger(this, "rotationOverlayMode", 0);
-	public OptionRange animations = new OptionRange(this, "animations", 2, 3);
-	public OptionBoolean customAnimations = new OptionBoolean(this, "customAnimations", true);
-	public OptionInteger playerListPosition = new OptionInteger(this, "playerListPosition", 2);
-	public OptionBoolean heldItemTooltips = new OptionBoolean(this, "heldItemTooltips", true);
-	public OptionFloat colorCorrection = new OptionFloat(this, "colorCorrection", 0.5f);
-	public OptionBoolean sneakToggle = new OptionBoolean(this, "sneakToggle", false);
-	public OptionFloat autosaveTimer = new OptionFloat(this, "autosaveTimer", 0.04166666666F);
-	public OptionBoolean enableItemDragging = new OptionBoolean(this, "enableItemDragging", true);
-	public OptionRange bloom = new OptionRange(this, "bloom", 0, 3);
-	public OptionEnum<RenderScale> renderScale = new OptionEnum<>(this, "renderScale", RenderScale.class, RenderScale.SCALE_100);
-	public OptionBoolean heatHaze = new OptionBoolean(this, "heatHaze", false);
-	public OptionBoolean alphaMenu = new OptionBoolean(this, "old", false);
-	public OptionBoolean enableItemClumping = new OptionBoolean(this, "enableItemClumping", true);
-	public OptionEnum itemDescriptions = new OptionEnum<>(this, "itemDescriptions", DescriptionPromptEnum.class, DescriptionPromptEnum.PROMPT);
-	public OptionBoolean turnWithVehicle = new OptionBoolean(this, "turnWithVehicle", true);
-	public OptionBoolean disableCrashHandler = new OptionBoolean(this, "disableCrashHandler", false);
-	public OptionBoolean enableMultiDrawRendering = new OptionBoolean(this, "enableMultiDrawRendering", true);
-	public OptionBoolean musicToasts = new OptionBoolean(this, "musicToasts", true);
-	public OptionEnum<MusicFrequency> musicFrequency = new OptionEnum<>(this, "musicFrequency", MusicFrequency.class, MusicFrequency.DEFAULT);
-
-	public OptionBoolean enableDevResourceLoading = new OptionBoolean(this, "enableDevResourceLoading", false);
-	public OptionBoolean downloadSoundfiles = new OptionBoolean(this, "downloadSoundfiles", true);
-	public OptionBoolean allowSoundOverrides = new OptionBoolean(this, "allowSoundOverrides", false);
-	public OptionBoolean loadAllSounds = new OptionBoolean(this, "loadAllSounds", false);
+	public @NotNull OptionFloat flightSpeed = new OptionFloat(this, "flightSpeed", 0.5f);
+	public @NotNull OptionFloat flightSmoothness = new OptionFloat(this, "flightSmoothness", 0.5f);
+
+	public @NotNull OptionBoolean invertMouse = new OptionBoolean(this, "invertYMouse", false);
+	public @NotNull OptionBoolean rawMouseInput = new OptionBoolean(this, "rawMouseInput", false);
+	public @NotNull OptionBoolean viewBobbing = new OptionBoolean(this, "bobView", true);
+	public @NotNull OptionBoolean advancedOpenGL = new OptionBoolean(this, "advancedOpengl", false);
+	public @NotNull OptionRange fancyGraphics = new OptionRange(this, "fancyGraphics", 1, 2);
+	public @NotNull OptionBoolean treeShadows = new OptionBoolean(this, "treeShadows", true);
+	public @NotNull OptionBoolean connectedGlass = new OptionBoolean(this, "connectedGlass", false);
+	public @NotNull OptionBoolean ambientOcclusion = new OptionBoolean(this, "ambientOcclusion", true);
+	public @NotNull OptionBoolean items3D = new OptionBoolean(this, "3Ditems", false);
+	public @NotNull OptionBoolean smoothCamera = new OptionBoolean(this, "smoothCamera", false);
+	public @NotNull OptionBoolean lockCamera = new OptionBoolean(this, "lockCamera", false);
+	public @NotNull OptionBoolean biomeWater = new OptionBoolean(this, "biomeWater", true);
+	public @NotNull OptionBoolean vignette = new OptionBoolean(this, "vignette", true);
+	public @NotNull OptionBoolean showPlayerList = new OptionBoolean(this, "showPlayerList", false);
+	public @NotNull OptionBoolean slimeParticles = new OptionBoolean(this, "slimeParticles", true);
+	public @NotNull OptionBoolean disableShaders = new OptionBoolean(this, "disableShaders", false);
+	public @NotNull OptionString shaderOverride = new OptionString(this, "shaderOverride", "");
+	public @NotNull OptionBoolean autoHit = new OptionBoolean(this, "autoHit", true);
+	public @NotNull OptionBoolean easyBridge = new OptionBoolean(this, "easyBridge", true);
+	public @NotNull OptionBoolean foodHealthRegenOverlay = new OptionBoolean(this, "foodHealthRegenOverlay", true);
+	public @NotNull OptionBoolean fpsInOverlay = new OptionBoolean(this, "fpsInOverlay", false);
+	public @NotNull OptionBoolean versionInOverlay = new OptionBoolean(this, "versionInOverlay", false);
+	public @NotNull OptionBoolean controllerSwapShoulderButtons = new OptionBoolean(this, "controllerSwapShoulderButtons", false);
+	public @NotNull OptionBoolean controllerSwapAB = new OptionBoolean(this, "controllerSwapAB", false);
+	public @NotNull OptionBoolean controllerSwapXY = new OptionBoolean(this, "controllerSwapXY", false);
+	public @NotNull OptionBoolean clouds = new OptionBoolean(this, "clouds", true);
+	public @NotNull OptionFloat cloudHeight = new OptionFloat(this, "cloudHeight", 0f);
+	public @NotNull OptionBoolean armorDurabilityOverlay = new OptionBoolean(this, "armorDurabilityOverlay", false);
+	public @NotNull OptionBoolean armorProtectionOverlay = new OptionBoolean(this, "armorProtectionOverlay", true);
+	public @NotNull OptionBoolean heldItemCountOverlay = new OptionBoolean(this, "heldItemCountOverlay", false);
+	public @NotNull OptionBoolean pauseOnLostFocus = new OptionBoolean(this, "pauseOnLostFocus", true);
+	public @NotNull OptionBoolean showDebugScreen = new OptionBoolean(this, "showDebugScreen", false);
+	public @NotNull OptionBoolean showFrameTimes = new OptionBoolean(this, "showFrameTimes", false);
+	public @NotNull OptionBoolean showItemDebugInfo = new OptionBoolean(this, "showItemDebugInfo", false);
+	public @NotNull OptionBoolean showChunkBorders = new OptionBoolean(this, "showChunkBorders", false);
+	public @NotNull OptionBoolean showCollisionBoxes = new OptionBoolean(this, "showCollisionBoxes", false);
+	public @NotNull OptionBoolean swapCraftingButtons = new OptionBoolean(this, "swapCraftingButtons", false);
+	public @NotNull OptionBoolean forceOnscreenKeyboard = new OptionBoolean(this, "forceOnscreenKeyboard", false);
+	public @NotNull OptionEnum<PlacementMode> placementMode = new OptionEnum<>(this, "placementMode", PlacementMode.class, PlacementMode.DEFAULT).setIsSlider(false);
+	public @NotNull OptionBoolean discordRichPresence = new OptionBoolean(this, "discordRichPresence", false);
+	public @NotNull OptionImmersiveMode immersiveMode = new OptionImmersiveMode(this);
+	public @NotNull OptionColor guiBackgroundColor = new OptionColor(this, "guiBackgroundColor", new Color().setARGB(0xc0101010));
+	public @NotNull OptionEnum<Difficulty> difficulty = new OptionEnum<>(this, "difficulty", Difficulty.class, Difficulty.NORMAL); // Stub for local difficulty setting
+	public @NotNull OptionInteger thirdPersonView = new OptionInteger(this, "thirdPersonView", 0);
+	public @NotNull OptionRange renderDistance = new OptionRange(this, "renderDistance", 12, 2, 32);
+	public @NotNull OptionBoolean enableVsync = new OptionBoolean(this, "enableVsync", false);
+	public @NotNull OptionEnum<ChatVisibility> chatVisibility = new OptionEnum<>(this, "chatVisibility", ChatVisibility.class, ChatVisibility.SHOW_ALL);
+	public @NotNull OptionRange customFpsLimit = new OptionRange(this,"customFpsLimit",0,241);
+	public @NotNull OptionInteger guiScale = new OptionInteger(this, "guiScale", 0);
+	public @NotNull OptionInteger overlayMode = new OptionInteger(this, "overlayMode", 0);
+	public @NotNull OptionInteger rotationOverlayMode = new OptionInteger(this, "rotationOverlayMode", 0);
+	public @NotNull OptionRange animations = new OptionRange(this, "animations", 2, 3);
+	public @NotNull OptionBoolean customAnimations = new OptionBoolean(this, "customAnimations", true);
+	public @NotNull OptionInteger playerListPosition = new OptionInteger(this, "playerListPosition", 2);
+	public @NotNull OptionBoolean heldItemTooltips = new OptionBoolean(this, "heldItemTooltips", true);
+	public @NotNull OptionFloat colorCorrection = new OptionFloat(this, "colorCorrection", 0.5f);
+	public @NotNull OptionBoolean sneakToggle = new OptionBoolean(this, "sneakToggle", false);
+	public @NotNull OptionFloat autosaveTimer = new OptionFloat(this, "autosaveTimer", 0.04166666666F);
+	public @NotNull OptionBoolean enableItemDragging = new OptionBoolean(this, "enableItemDragging", true);
+	public @NotNull OptionRange bloom = new OptionRange(this, "bloom", 0, 3);
+	public @NotNull OptionEnum<RenderScale> renderScale = new OptionEnum<>(this, "renderScale", RenderScale.class, RenderScale.SCALE_100);
+	public @NotNull OptionBoolean heatHaze = new OptionBoolean(this, "heatHaze", false);
+	public @NotNull OptionBoolean alphaMenu = new OptionBoolean(this, "old", false);
+	public @NotNull OptionBoolean enableItemClumping = new OptionBoolean(this, "enableItemClumping", true);
+	public @NotNull OptionEnum<DescriptionPromptEnum> itemDescriptions = new OptionEnum<>(this, "itemDescriptions", DescriptionPromptEnum.class, DescriptionPromptEnum.PROMPT);
+	public @NotNull OptionBoolean turnWithVehicle = new OptionBoolean(this, "turnWithVehicle", true);
+	public @NotNull OptionBoolean disableCrashHandler = new OptionBoolean(this, "disableCrashHandler", false);
+	public @NotNull OptionBoolean enableMultiDrawRendering = new OptionBoolean(this, "enableMultiDrawRendering", true);
+	public @NotNull OptionBoolean musicToasts = new OptionBoolean(this, "musicToasts", true);
+	public @NotNull OptionEnum<MusicFrequency> musicFrequency = new OptionEnum<>(this, "musicFrequency", MusicFrequency.class, MusicFrequency.DEFAULT);
+
+	public @NotNull OptionBoolean enableDevResourceLoading = new OptionBoolean(this, "enableDevResourceLoading", false);
+	public @NotNull OptionBoolean downloadSoundfiles = new OptionBoolean(this, "downloadSoundfiles", true);
+	public @NotNull OptionBoolean allowSoundOverrides = new OptionBoolean(this, "allowSoundOverrides", false);
+	public @NotNull OptionBoolean loadAllSounds = new OptionBoolean(this, "loadAllSounds", false);
 	
-	public OptionBoolean overlayShowCoords = new OptionBoolean(this, "overlayShowCoords", true);
-	public OptionBoolean overlayShowDirection = new OptionBoolean(this, "overlayShowDirection", true);
-	public OptionBoolean overlayShowTime = new OptionBoolean(this, "overlayShowTime", true);
-	public OptionBoolean overlayShowSeason = new OptionBoolean(this, "overlayShowSeason", true);
-	public OptionBoolean overlayShowWeather = new OptionBoolean(this, "overlayShowWeather", true);
-	public OptionBoolean overlayShowBiome = new OptionBoolean(this, "overlayShowBiome", true);
+	public @NotNull OptionBoolean overlayShowCoords = new OptionBoolean(this, "overlayShowCoords", true);
+	public @NotNull OptionBoolean overlayShowDirection = new OptionBoolean(this, "overlayShowDirection", true);
+	public @NotNull OptionBoolean overlayShowTime = new OptionBoolean(this, "overlayShowTime", true);
+	public @NotNull OptionBoolean overlayShowSeason = new OptionBoolean(this, "overlayShowSeason", true);
+	public @NotNull OptionBoolean overlayShowWeather = new OptionBoolean(this, "overlayShowWeather", true);
+	public @NotNull OptionBoolean overlayShowBiome = new OptionBoolean(this, "overlayShowBiome", true);
 	
-	public OptionBoolean[] overlayElements = new OptionBoolean[] { overlayShowCoords, overlayShowDirection, overlayShowTime, overlayShowSeason, overlayShowWeather, overlayShowBiome };
+	public @NotNull OptionBoolean @NotNull [] overlayElements = new OptionBoolean[] { overlayShowCoords, overlayShowDirection, overlayShowTime, overlayShowSeason, overlayShowWeather, overlayShowBiome };
 	
-	public OptionString lastServer = new OptionString(this, "lastServer", "");
-	public OptionString skin = new OptionString(this, "skin", "Default");
-	public OptionString selectedController = new OptionString(this, "selectedController", "");
-    public OptionString language = new OptionString(this, "language", "en_US");
+	public @NotNull OptionString lastServer = new OptionString(this, "lastServer", "");
+	public @NotNull OptionString skin = new OptionString(this, "skin", "Default");
+	public @NotNull OptionString selectedController = new OptionString(this, "selectedController", "");
+    public @NotNull OptionString language = new OptionString(this, "language", "en_US");
 	
-	public OptionRange mipmapLevels = new OptionRange(this, "mipmapLevels", 0, 5);
-	public OptionEnum<MipmapType> mipmapType = new OptionEnum<>(this, "mipmapType", MipmapType.class, MipmapType.SMOOTH);
-
-	public OptionBoolean fovModification = new OptionBoolean(this, "fov.modification", true);
-	public OptionBoolean screenMotionEffects = new OptionBoolean(this, "screen.motion.effects", true);
-
-	public OptionBoolean fullscreen = new OptionBoolean(this, "fullscreen", Minecraft.isClientASteamDeck());
-	public OptionBoolean borderlessFullscreen = new OptionBoolean(this, "borderlessFullscreen", true);
-	public OptionBoolean startInFullscreen = new OptionBoolean(this, "startInFullscreen", true);
-	public OptionTooltip tooltipStyle = new OptionTooltip(this, "tooltipStyle", "default");
-	public OptionFont font = new OptionFont(this, "font", Fonts.DEFAULT);
-	public OptionEnum<LightmapStyle> lightmapStyle = new OptionEnum<>(this, "lightmapStyle", LightmapStyle.class, LightmapStyle.GRAY);
-	public OptionBoolean customLightmap = new OptionBoolean(this, "customLightmap", true);
-	public OptionBoolean fog = new OptionBoolean(this, "fog", true);
-	public OptionBoolean hideUndiscoveredItems = new OptionBoolean(this, "hideUndiscoveredItems", true);
-	public OptionBoolean muteOnLostFocus = new OptionBoolean(this, "muteOnLostFocus", false);
-	public OptionBoolean aurora = new OptionBoolean(this, "aurora", true);
-	public OptionBoolean mobVariants = new OptionBoolean(this, "mobVariants", true);
-	public OptionEnum<Colorblindness> colorblindnessFix = new OptionEnum<>(this, "colorblindnessFix", Colorblindness.class, Colorblindness.NONE);
-	public OptionBoolean subtitles = new OptionBoolean(this, "subtitles", false);
-	public OptionBoolean developerMode = new OptionBoolean(this, "developerMode", false);
-	public OptionBoolean enableHolidayTextures = new OptionBoolean(this, "enableHolidayTextures", true);
-	public OptionBoolean dynamicCursor = new OptionBoolean(this, "dynamicCursor", true);
-	public OptionBoolean devModels = new OptionBoolean(this, "devModels", true);
-
-	public OptionBoolean playerLeftHanded = new OptionBoolean(this, "player.left.handed", false);
-	public OptionBoolean playerCape = new OptionBoolean(this, "player.cape", true);
-	public OptionBoolean playerHat = new OptionBoolean(this, "player.hat", true);
-	public OptionBoolean playerJacket = new OptionBoolean(this, "player.jacket", true);
-	public OptionBoolean playerSleeveLeft = new OptionBoolean(this, "player.sleeve.left", true);
-	public OptionBoolean playerSleeveRight = new OptionBoolean(this, "player.sleeve.right", true);
-	public OptionBoolean playerPantLeft = new OptionBoolean(this, "player.pant.left", true);
-	public OptionBoolean playerPantRight = new OptionBoolean(this, "player.pant.right", true);
-	public OptionBoolean doJCECheck = new OptionBoolean(this, "doJCECheck", true);
-	public OptionString uuidServer = new OptionString(this, "uuidServer", "https://api.minecraftservices.com/minecraft/profile/lookup/name/%s");
-
-	public KeyBinding keyAttack = new KeyBinding("key.attack").setDefault(InputDevice.mouse, 0);
-	public KeyBinding keyInteract = new KeyBinding("key.interact").setDefault(InputDevice.mouse, 1);
-	public KeyBinding keyPickBlock = new KeyBinding("key.pickBlock").setDefault(InputDevice.mouse, 2);
-	public KeyBinding keySortInventory = new KeyBinding("key.sortInventory").setDefault(InputDevice.mouse, 2);
-	public KeyBinding keyForward = new KeyBinding("key.forward").setDefault(InputDevice.keyboard, KEY_W);
-	public KeyBinding keyLeft = new KeyBinding("key.left").setDefault(InputDevice.keyboard, KEY_A);
-	public KeyBinding keyBack = new KeyBinding("key.back").setDefault(InputDevice.keyboard, KEY_S);
-	public KeyBinding keyRight = new KeyBinding("key.right").setDefault(InputDevice.keyboard, KEY_D);
-	public KeyBinding keyJump = new KeyBinding("key.jump").setDefault(InputDevice.keyboard, KEY_SPACE);
-	public KeyBinding keyInventory = new KeyBinding("key.inventory").setDefault(InputDevice.keyboard, KEY_E);
-	public KeyBinding keyDrop = new KeyBinding("key.drop").setDefault(InputDevice.keyboard, KEY_Q);
-	public KeyBinding keyChat = new KeyBinding("key.chat").setDefault(InputDevice.keyboard, KEY_T);
-	public KeyBinding keyCommand = new KeyBinding("key.command").setDefault(InputDevice.keyboard, KEY_SLASH);
-	public KeyBinding keyToggleFog = new KeyBinding("key.fog");
-	public KeyBinding keyToggleGamma = new KeyBinding("key.gamma");
-	public KeyBinding keySneak = new KeyBinding("key.sneak").setDefault(InputDevice.keyboard, KEY_LSHIFT);
-	public KeyBinding keyFly = new KeyBinding("key.fly").setDefault(InputDevice.keyboard, KEY_LCONTROL);
-	public KeyBinding keyGuidebook = new KeyBinding("key.guidebook").setDefault(InputDevice.keyboard, KEY_R);
-	public KeyBinding keyDescription = new KeyBinding("key.description").setDefault(InputDevice.keyboard, KEY_LCONTROL);
-	public KeyBinding keyShowRecipe = new KeyBinding("key.showRecipe").setDefault(InputDevice.keyboard, KEY_R);
-	public KeyBinding keyShowUsage = new KeyBinding("key.showUsage").setDefault(InputDevice.keyboard, KEY_U);
-	public KeyBinding keyHotBarLeft = new KeyBinding("key.hotbar.left").setDefault(InputDevice.keyboard, KEY_COMMA);
-	public KeyBinding keyHotBarRight = new KeyBinding("key.hotbar.right").setDefault(InputDevice.keyboard, KEY_PERIOD);
-	public KeyBinding keyHotBarSwitch = new KeyBinding("key.hotbar.switch").setDefault(InputDevice.keyboard, KEY_TAB);
-
-	public KeyBinding keyHideGui = new KeyBinding("key.immersiveMode").setDefault(InputDevice.keyboard, KEY_F1);
-	public KeyBinding keyScreenshot = new KeyBinding("key.screenshot").setDefault(InputDevice.keyboard, KEY_F2);
-	public KeyBinding keyToggleDebug = new KeyBinding("key.toggleDebug").setDefault(InputDevice.keyboard, KEY_F3);
-	public KeyBinding keyToggleOverlay = new KeyBinding("key.toggleOverlay").setDefault(InputDevice.keyboard, KEY_F4);
-	public KeyBinding keySwitchPerspective = new KeyBinding("key.switchPerspective").setDefault(InputDevice.keyboard, KEY_F5);
-	public KeyBinding keyCinematicCamera = new KeyBinding("key.cinematicCamera").setDefault(InputDevice.keyboard, KEY_F8);
-	public KeyBinding keyFullScreen = new KeyBinding("key.fullscreen").setDefault(InputDevice.keyboard, KEY_F11);
-	public KeyBinding keyReleaseCursor = new KeyBinding("key.debug.releasecursor").setDefault(InputDevice.keyboard, KEY_F12);
-
-	public KeyBinding keyHotBarSlot1 = new KeyBinding("key.hotbar.1").setDefault(InputDevice.keyboard, KEY_1);
-	public KeyBinding keyHotBarSlot2 = new KeyBinding("key.hotbar.2").setDefault(InputDevice.keyboard, KEY_2);
-	public KeyBinding keyHotBarSlot3 = new KeyBinding("key.hotbar.3").setDefault(InputDevice.keyboard, KEY_3);
-	public KeyBinding keyHotBarSlot4 = new KeyBinding("key.hotbar.4").setDefault(InputDevice.keyboard, KEY_4);
-	public KeyBinding keyHotBarSlot5 = new KeyBinding("key.hotbar.5").setDefault(InputDevice.keyboard, KEY_5);
-	public KeyBinding keyHotBarSlot6 = new KeyBinding("key.hotbar.6").setDefault(InputDevice.keyboard, KEY_6);
-	public KeyBinding keyHotBarSlot7 = new KeyBinding("key.hotbar.7").setDefault(InputDevice.keyboard, KEY_7);
-	public KeyBinding keyHotBarSlot8 = new KeyBinding("key.hotbar.8").setDefault(InputDevice.keyboard, KEY_8);
-	public KeyBinding keyHotBarSlot9 = new KeyBinding("key.hotbar.9").setDefault(InputDevice.keyboard, KEY_9);
-
-	public KeyBinding keyLookLeft = new KeyBinding("key.look.left").setDefault(InputDevice.keyboard, KEY_LEFT);
-	public KeyBinding keyLookRight = new KeyBinding("key.look.right").setDefault(InputDevice.keyboard, KEY_RIGHT);
-	public KeyBinding keyLookUp = new KeyBinding("key.look.up").setDefault(InputDevice.keyboard, KEY_UP);
-	public KeyBinding keyLookDown = new KeyBinding("key.look.down").setDefault(InputDevice.keyboard, KEY_DOWN);
-	public KeyBinding keyCenterView = new KeyBinding("key.look.center").setDefault(InputDevice.keyboard, KEY_END);
-	public KeyBinding keyZoom = new KeyBinding("key.zoom").setDefault(InputDevice.keyboard, KEY_C);
-	public KeyBinding keyPlayerList = new KeyBinding("key.playerList").setDefault(InputDevice.keyboard, KEY_L);
-	public KeyBinding keyPhotoMode = new KeyBinding("key.photoMode").setDefault(InputDevice.keyboard, KEY_P);
-	public KeyBinding keyLockRotation = new KeyBinding("key.lockRotation").setDefault(InputDevice.keyboard, KEY_Z);
-	public KeyBinding keyAutoWalk = new KeyBinding("key.autoWalk");
-	public KeyBinding keyEasyBridge = new KeyBinding("key.easyBridge");
-	public KeyBinding keySprint = new KeyBinding("key.sprint");
-	public KeyBinding keyOpenAchievements = new KeyBinding("key.openAchievements");
-	public KeyBinding keyOpenStatistics = new KeyBinding("key.openStatistics");
-	public KeyBinding keyShowConsole = new KeyBinding("key.showConsole").setDefault(InputDevice.keyboard, KEY_GRAVE);
-	public List<KeyBinding> debugsKeys = new ArrayList<>();
-	public KeyBinding keyReload = new KeyBinding("key.debug.reload").setDefault(InputDevice.keyboard, KEY_R);
-	public KeyBinding keySwitchGamemode = new KeyBinding("key.debug.gamemode").setDefault(InputDevice.keyboard, KEY_N);
-	public KeyBinding keyDumpTextures = new KeyBinding("key.debug.dumptextures").setDefault(InputDevice.keyboard, KEY_D);
-	public KeyBinding keyFullbright = new KeyBinding("key.debug.fullbright").setDefault(InputDevice.keyboard, KEY_F);
-	public KeyBinding keyLightmaps = new KeyBinding("key.debug.lightmap").setDefault(InputDevice.keyboard, KEY_L);
-	public KeyBinding keyCollisionBoxes = new KeyBinding("key.debug.collision").setDefault(InputDevice.keyboard, KEY_B);
-	public KeyBinding keyChunkBorders = new KeyBinding("key.debug.chunkborders").setDefault(InputDevice.keyboard, KEY_G);
-	public KeyBinding keyClearChat = new KeyBinding("key.debug.clearchat").setDefault(InputDevice.keyboard, KEY_C);
-	public KeyBinding keyPauseLostFocus = new KeyBinding("key.debug.pauseFocus").setDefault(InputDevice.keyboard, KEY_P);
-	public KeyBinding keyToggleItemInfo = new KeyBinding("key.debug.iteminfo").setDefault(InputDevice.keyboard, KEY_H);
-	public KeyBinding keyReloadChunks = new KeyBinding("key.debug.reloadchunks").setDefault(InputDevice.keyboard, KEY_A);
-	public KeyBinding keySmoothLighting = new KeyBinding("key.debug.smoothlighting").setDefault(InputDevice.keyboard, KEY_S);
-	public KeyBinding keyShowShortcuts = new KeyBinding("key.debug.shortcuts").setDefault(InputDevice.keyboard, KEY_Q);
-	public KeyBinding keyToggleTextureAtlas = new KeyBinding("key.debug.textureAtlas");
-	public KeyBinding keyLoadChunksQuickly = new KeyBinding("key.debug.loadChunksQuickly");
-
-	public static final List<KeyBinding> keys = new ArrayList<>();
-	public static final List<Option<?>> options = new ArrayList<>();
-	public List<Option<?>> getAllOptions(){
+	public @NotNull OptionRange mipmapLevels = new OptionRange(this, "mipmapLevels", 0, 5);
+	public @NotNull OptionEnum<MipmapType> mipmapType = new OptionEnum<>(this, "mipmapType", MipmapType.class, MipmapType.SMOOTH);
+
+	public @NotNull OptionBoolean fovModification = new OptionBoolean(this, "fov.modification", true);
+	public @NotNull OptionBoolean screenMotionEffects = new OptionBoolean(this, "screen.motion.effects", true);
+
+	public @NotNull OptionBoolean fullscreen = new OptionBoolean(this, "fullscreen", Minecraft.isClientASteamDeck());
+	public @NotNull OptionBoolean borderlessFullscreen = new OptionBoolean(this, "borderlessFullscreen", true);
+	public @NotNull OptionBoolean startInFullscreen = new OptionBoolean(this, "startInFullscreen", true);
+	public @NotNull OptionTooltip tooltipStyle = new OptionTooltip(this, "tooltipStyle", "default");
+	public @NotNull OptionFont font = new OptionFont(this, "font", Fonts.DEFAULT);
+	public @NotNull OptionEnum<LightmapStyle> lightmapStyle = new OptionEnum<>(this, "lightmapStyle", LightmapStyle.class, LightmapStyle.GRAY);
+	public @NotNull OptionBoolean customLightmap = new OptionBoolean(this, "customLightmap", true);
+	public @NotNull OptionBoolean fog = new OptionBoolean(this, "fog", true);
+	public @NotNull OptionBoolean hideUndiscoveredItems = new OptionBoolean(this, "hideUndiscoveredItems", true);
+	public @NotNull OptionBoolean muteOnLostFocus = new OptionBoolean(this, "muteOnLostFocus", false);
+	public @NotNull OptionBoolean aurora = new OptionBoolean(this, "aurora", true);
+	public @NotNull OptionBoolean mobVariants = new OptionBoolean(this, "mobVariants", true);
+	public @NotNull OptionEnum<Colorblindness> colorblindnessFix = new OptionEnum<>(this, "colorblindnessFix", Colorblindness.class, Colorblindness.NONE);
+	public @NotNull OptionBoolean subtitles = new OptionBoolean(this, "subtitles", false);
+	public @NotNull OptionBoolean developerMode = new OptionBoolean(this, "developerMode", false);
+	public @NotNull OptionBoolean viewSupportMode = new OptionBoolean(this, "viewSupportMode", false);
+	public @NotNull OptionBoolean enableHolidayTextures = new OptionBoolean(this, "enableHolidayTextures", true);
+	public @NotNull OptionBoolean dynamicCursor = new OptionBoolean(this, "dynamicCursor", true);
+	public @NotNull OptionBoolean devModels = new OptionBoolean(this, "devModels", true);
+
+	public @NotNull OptionBoolean playerLeftHanded = new OptionBoolean(this, "player.left.handed", false);
+	public @NotNull OptionBoolean playerCape = new OptionBoolean(this, "player.cape", true);
+	public @NotNull OptionBoolean playerHat = new OptionBoolean(this, "player.hat", true);
+	public @NotNull OptionBoolean playerJacket = new OptionBoolean(this, "player.jacket", true);
+	public @NotNull OptionBoolean playerSleeveLeft = new OptionBoolean(this, "player.sleeve.left", true);
+	public @NotNull OptionBoolean playerSleeveRight = new OptionBoolean(this, "player.sleeve.right", true);
+	public @NotNull OptionBoolean playerPantLeft = new OptionBoolean(this, "player.pant.left", true);
+	public @NotNull OptionBoolean playerPantRight = new OptionBoolean(this, "player.pant.right", true);
+	public @NotNull OptionBoolean doJCECheck = new OptionBoolean(this, "doJCECheck", true);
+	public @NotNull OptionString uuidServer = new OptionString(this, "uuidServer", "https://api.minecraftservices.com/minecraft/profile/lookup/name/%s");
+
+	public @NotNull KeyBinding keyAttack = new KeyBinding("key.attack").setDefault(InputDevice.mouse, 0);
+	public @NotNull KeyBinding keyInteract = new KeyBinding("key.interact").setDefault(InputDevice.mouse, 1);
+	public @NotNull KeyBinding keyPickBlock = new KeyBinding("key.pickBlock").setDefault(InputDevice.mouse, 2);
+	public @NotNull KeyBinding keySortInventory = new KeyBinding("key.sortInventory").setDefault(InputDevice.mouse, 2);
+	public @NotNull KeyBinding keyForward = new KeyBinding("key.forward").setDefault(InputDevice.keyboard, KEY_W);
+	public @NotNull KeyBinding keyLeft = new KeyBinding("key.left").setDefault(InputDevice.keyboard, KEY_A);
+	public @NotNull KeyBinding keyBack = new KeyBinding("key.back").setDefault(InputDevice.keyboard, KEY_S);
+	public @NotNull KeyBinding keyRight = new KeyBinding("key.right").setDefault(InputDevice.keyboard, KEY_D);
+	public @NotNull KeyBinding keyJump = new KeyBinding("key.jump").setDefault(InputDevice.keyboard, KEY_SPACE);
+	public @NotNull KeyBinding keyInventory = new KeyBinding("key.inventory").setDefault(InputDevice.keyboard, KEY_E);
+	public @NotNull KeyBinding keyDrop = new KeyBinding("key.drop").setDefault(InputDevice.keyboard, KEY_Q);
+	public @NotNull KeyBinding keyChat = new KeyBinding("key.chat").setDefault(InputDevice.keyboard, KEY_T);
+	public @NotNull KeyBinding keyCommand = new KeyBinding("key.command").setDefault(InputDevice.keyboard, KEY_SLASH);
+	public @NotNull KeyBinding keyToggleFog = new KeyBinding("key.fog");
+	public @NotNull KeyBinding keyToggleGamma = new KeyBinding("key.gamma");
+	public @NotNull KeyBinding keySneak = new KeyBinding("key.sneak").setDefault(InputDevice.keyboard, KEY_LSHIFT);
+	public @NotNull KeyBinding keyFly = new KeyBinding("key.fly").setDefault(InputDevice.keyboard, KEY_LCONTROL);
+	public @NotNull KeyBinding keyGuidebook = new KeyBinding("key.guidebook").setDefault(InputDevice.keyboard, KEY_R);
+	public @NotNull KeyBinding keyDescription = new KeyBinding("key.description").setDefault(InputDevice.keyboard, KEY_LCONTROL);
+	public @NotNull KeyBinding keyShowRecipe = new KeyBinding("key.showRecipe").setDefault(InputDevice.keyboard, KEY_R);
+	public @NotNull KeyBinding keyShowUsage = new KeyBinding("key.showUsage").setDefault(InputDevice.keyboard, KEY_U);
+	public @NotNull KeyBinding keyHotBarLeft = new KeyBinding("key.hotbar.left").setDefault(InputDevice.keyboard, KEY_COMMA);
+	public @NotNull KeyBinding keyHotBarRight = new KeyBinding("key.hotbar.right").setDefault(InputDevice.keyboard, KEY_PERIOD);
+	public @NotNull KeyBinding keyHotBarSwitch = new KeyBinding("key.hotbar.switch").setDefault(InputDevice.keyboard, KEY_TAB);
+
+	public @NotNull KeyBinding keyHideGui = new KeyBinding("key.immersiveMode").setDefault(InputDevice.keyboard, KEY_F1);
+	public @NotNull KeyBinding keyScreenshot = new KeyBinding("key.screenshot").setDefault(InputDevice.keyboard, KEY_F2);
+	public @NotNull KeyBinding keyToggleDebug = new KeyBinding("key.toggleDebug").setDefault(InputDevice.keyboard, KEY_F3);
+	public @NotNull KeyBinding keyToggleOverlay = new KeyBinding("key.toggleOverlay").setDefault(InputDevice.keyboard, KEY_F4);
+	public @NotNull KeyBinding keySwitchPerspective = new KeyBinding("key.switchPerspective").setDefault(InputDevice.keyboard, KEY_F5);
+	public @NotNull KeyBinding keyCinematicCamera = new KeyBinding("key.cinematicCamera").setDefault(InputDevice.keyboard, KEY_F8);
+	public @NotNull KeyBinding keyFullScreen = new KeyBinding("key.fullscreen").setDefault(InputDevice.keyboard, KEY_F11);
+	public @NotNull KeyBinding keyReleaseCursor = new KeyBinding("key.debug.releasecursor").setDefault(InputDevice.keyboard, KEY_F12);
+
+	public @NotNull KeyBinding keyHotBarSlot1 = new KeyBinding("key.hotbar.1").setDefault(InputDevice.keyboard, KEY_1);
+	public @NotNull KeyBinding keyHotBarSlot2 = new KeyBinding("key.hotbar.2").setDefault(InputDevice.keyboard, KEY_2);
+	public @NotNull KeyBinding keyHotBarSlot3 = new KeyBinding("key.hotbar.3").setDefault(InputDevice.keyboard, KEY_3);
+	public @NotNull KeyBinding keyHotBarSlot4 = new KeyBinding("key.hotbar.4").setDefault(InputDevice.keyboard, KEY_4);
+	public @NotNull KeyBinding keyHotBarSlot5 = new KeyBinding("key.hotbar.5").setDefault(InputDevice.keyboard, KEY_5);
+	public @NotNull KeyBinding keyHotBarSlot6 = new KeyBinding("key.hotbar.6").setDefault(InputDevice.keyboard, KEY_6);
+	public @NotNull KeyBinding keyHotBarSlot7 = new KeyBinding("key.hotbar.7").setDefault(InputDevice.keyboard, KEY_7);
+	public @NotNull KeyBinding keyHotBarSlot8 = new KeyBinding("key.hotbar.8").setDefault(InputDevice.keyboard, KEY_8);
+	public @NotNull KeyBinding keyHotBarSlot9 = new KeyBinding("key.hotbar.9").setDefault(InputDevice.keyboard, KEY_9);
+
+	public @NotNull KeyBinding keyLookLeft = new KeyBinding("key.look.left").setDefault(InputDevice.keyboard, KEY_LEFT);
+	public @NotNull KeyBinding keyLookRight = new KeyBinding("key.look.right").setDefault(InputDevice.keyboard, KEY_RIGHT);
+	public @NotNull KeyBinding keyLookUp = new KeyBinding("key.look.up").setDefault(InputDevice.keyboard, KEY_UP);
+	public @NotNull KeyBinding keyLookDown = new KeyBinding("key.look.down").setDefault(InputDevice.keyboard, KEY_DOWN);
+	public @NotNull KeyBinding keyCenterView = new KeyBinding("key.look.center").setDefault(InputDevice.keyboard, KEY_END);
+	public @NotNull KeyBinding keyZoom = new KeyBinding("key.zoom").setDefault(InputDevice.keyboard, KEY_C);
+	public @NotNull KeyBinding keyPlayerList = new KeyBinding("key.playerList").setDefault(InputDevice.keyboard, KEY_L);
+	public @NotNull KeyBinding keyPhotoMode = new KeyBinding("key.photoMode").setDefault(InputDevice.keyboard, KEY_P);
+	public @NotNull KeyBinding keyLockRotation = new KeyBinding("key.lockRotation").setDefault(InputDevice.keyboard, KEY_Z);
+	public @NotNull KeyBinding keyAutoWalk = new KeyBinding("key.autoWalk");
+	public @NotNull KeyBinding keyEasyBridge = new KeyBinding("key.easyBridge");
+	public @NotNull KeyBinding keySprint = new KeyBinding("key.sprint");
+	public @NotNull KeyBinding keyOpenAchievements = new KeyBinding("key.openAchievements");
+	public @NotNull KeyBinding keyOpenStatistics = new KeyBinding("key.openStatistics");
+	public @NotNull KeyBinding keyShowConsole = new KeyBinding("key.showConsole").setDefault(InputDevice.keyboard, KEY_GRAVE);
+	public @NotNull List<KeyBinding> debugsKeys = new ArrayList<>();
+	public @NotNull KeyBinding keyReload = new KeyBinding("key.debug.reload").setDefault(InputDevice.keyboard, KEY_R);
+	public @NotNull KeyBinding keySwitchGamemode = new KeyBinding("key.debug.gamemode").setDefault(InputDevice.keyboard, KEY_N);
+	public @NotNull KeyBinding keyDumpTextures = new KeyBinding("key.debug.dumptextures").setDefault(InputDevice.keyboard, KEY_D);
+	public @NotNull KeyBinding keyFullbright = new KeyBinding("key.debug.fullbright").setDefault(InputDevice.keyboard, KEY_F);
+	public @NotNull KeyBinding keyLightmaps = new KeyBinding("key.debug.lightmap").setDefault(InputDevice.keyboard, KEY_L);
+	public @NotNull KeyBinding keyCollisionBoxes = new KeyBinding("key.debug.collision").setDefault(InputDevice.keyboard, KEY_B);
+	public @NotNull KeyBinding keyChunkBorders = new KeyBinding("key.debug.chunkborders").setDefault(InputDevice.keyboard, KEY_G);
+	public @NotNull KeyBinding keyClearChat = new KeyBinding("key.debug.clearchat").setDefault(InputDevice.keyboard, KEY_C);
+	public @NotNull KeyBinding keyPauseLostFocus = new KeyBinding("key.debug.pauseFocus").setDefault(InputDevice.keyboard, KEY_P);
+	public @NotNull KeyBinding keyToggleItemInfo = new KeyBinding("key.debug.iteminfo").setDefault(InputDevice.keyboard, KEY_H);
+	public @NotNull KeyBinding keyReloadChunks = new KeyBinding("key.debug.reloadchunks").setDefault(InputDevice.keyboard, KEY_A);
+	public @NotNull KeyBinding keySmoothLighting = new KeyBinding("key.debug.smoothlighting").setDefault(InputDevice.keyboard, KEY_S);
+	public @NotNull KeyBinding keyShowShortcuts = new KeyBinding("key.debug.shortcuts").setDefault(InputDevice.keyboard, KEY_Q);
+	public @NotNull KeyBinding keyToggleTextureAtlas = new KeyBinding("key.debug.textureAtlas");
+	public @NotNull KeyBinding keyLoadChunksQuickly = new KeyBinding("key.debug.loadChunksQuickly");
+
+	public static final @NotNull List<@NotNull KeyBinding> keys = new ArrayList<>();
+	public static final @NotNull List<@NotNull Option<?>> options = new ArrayList<>();
+	public @NotNull List<@NotNull Option<?>> getAllOptions(){
 		return options;
 	}
 	
@@ -309,7 +312,7 @@ public class GameSettings {
 		saveOptions();
 	}
 
-	public String getDisplayString(Option<?> option) {
+	public @NotNull String getDisplayString(Option<?> option) {
 		if (option == null) return "";
 		I18n trans = I18n.getInstance();
 		if (option instanceof OptionFloat) {
@@ -453,7 +456,7 @@ public class GameSettings {
 			
 			return trans.translateKey("options." + optionEnum.name+"." + key);
 		}
-		return option.value.toString();
+		return emptyStringIfNull(option.value.toString());
 	}
 
 	public void optionChanged(Option<?> option) {
diff --git a/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java b/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
index f38de4f2f..62ed5f654 100644
--- a/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
+++ b/game/client/src/main/java/net/minecraft/client/option/KeyBinding.java
@@ -5,6 +5,8 @@ import java.util.Map;
 
 import net.minecraft.client.input.InputDevice;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class KeyBinding {
 	private static Map<Character, InputDevice> charToInputDeviceMap = new HashMap<>();
@@ -28,10 +30,10 @@ public class KeyBinding {
 	
 	private final String id;
 	
-	private InputDevice inputDevice;
+	private @Nullable InputDevice inputDevice;
 	private int keyCode = -1;
 
-	private InputDevice defaultInputDevice = null;
+	private @Nullable InputDevice defaultInputDevice = null;
 	private int defaultKeyCode = -1;
 
 	public KeyBinding(String id) {
@@ -41,7 +43,7 @@ public class KeyBinding {
 		GameSettings.keys.add(this);
 	}
 
-	public KeyBinding setDefault(InputDevice device, int keyCode) {
+	public @NotNull KeyBinding setDefault(final @Nullable InputDevice device, final int keyCode) {
 		if(device != null && !device.isKeyCodeValid(keyCode)) {
 			throw new RuntimeException("Key code " + keyCode + " is not valid for input device " + device);
 		}
@@ -49,26 +51,26 @@ public class KeyBinding {
 		this.defaultInputDevice = device;
 		this.defaultKeyCode = keyCode;
 		
-		return bind(device, keyCode);
+		return this.bind(device, keyCode);
 	}
 	
-	public KeyBinding bind(InputDevice device, int keyCode) {
-		if(device.isKeyCodeValid(keyCode)) {
+	public @NotNull KeyBinding bind(final @Nullable InputDevice device, final int keyCode) {
+		if(device != null && device.isKeyCodeValid(keyCode)) {
 			this.keyCode = keyCode;
 			this.inputDevice = device;	
-		}else {
-			unbind();
+		} else {
+            this.unbind();
 		}
 		return this;
 	}
 	
-	public KeyBinding unbind() {
+	public @NotNull KeyBinding unbind() {
 		this.keyCode = -1;
 		this.inputDevice = null;
 		return this;
 	}
 
-	public KeyBinding resetToDefault() {
+	public @NotNull KeyBinding resetToDefault() {
 		this.keyCode = defaultKeyCode;
 		this.inputDevice = defaultInputDevice;
 		return this;
diff --git a/game/client/src/main/java/net/minecraft/client/option/Option.java b/game/client/src/main/java/net/minecraft/client/option/Option.java
index 7291ae77c..c76c55881 100644
--- a/game/client/src/main/java/net/minecraft/client/option/Option.java
+++ b/game/client/src/main/java/net/minecraft/client/option/Option.java
@@ -2,19 +2,22 @@ package net.minecraft.client.option;
 
 import net.minecraft.client.gui.paged.CallbackComponent;
 import net.minecraft.core.lang.I18n;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static net.minecraft.core.util.Util.emptyStringIfNull;
+
 public abstract class Option<E> {
 
-	public final GameSettings gameSettings;
-	public final String name;
-	public E value;
-	protected final E defaultValue;
+	public final @NotNull GameSettings gameSettings;
+	public final @NotNull String name;
+	public @NotNull E value;
+	protected final @NotNull E defaultValue;
 	protected final List<OptionCallback<E>> callbacks = new ArrayList<>();
 
-	public Option(GameSettings gameSettings, String name, E defaultValue) {
+	public Option(final @NotNull GameSettings gameSettings, final @NotNull String name, final @NotNull E defaultValue) {
 		this.gameSettings = gameSettings;
 		this.name = name;
 		this.value = defaultValue;
@@ -22,47 +25,47 @@ public abstract class Option<E> {
 		GameSettings.options.add(this);
 	}
 
-	public void set(E value) {
+	public void set(final @NotNull E value) {
 		this.value = value;
 	}
 
-	public void addCallback(OptionCallback<E> callback) {
+	public void addCallback(final @NotNull OptionCallback<E> callback) {
 		this.callbacks.add(callback);
 	}
 
-	public abstract void parse(String string);
+	public abstract void parse(final @NotNull String string);
 
 	public void onUpdate() {
-		for (final OptionCallback<E> callback : this.callbacks) {
+		for (final @NotNull OptionCallback<E> callback : this.callbacks) {
 			callback.onUpdate(this);
 		}
-        gameSettings.optionChanged(this);
+        this.gameSettings.optionChanged(this);
     }
 
-	public String getDisplayString() {
-        return gameSettings.getDisplayString(this);
+	public @NotNull String getDisplayString() {
+        return this.gameSettings.getDisplayString(this);
     }
 
-	public String getDisplayStringValue() {
-        return gameSettings.getDisplayString(this);
+	public @NotNull String getDisplayStringValue() {
+        return this.gameSettings.getDisplayString(this);
     }
 
-	public String getDisplayStringName() {
+	public @NotNull String getDisplayStringName() {
 		return I18n.getInstance().translateKey("options." + this.name);
 	}
 
 	/**
 	 * The String that is saved to the options.txt file. Don't include spaces!
 	 */
-	public String getValueString() {
-		return value.toString();
+	public @NotNull String getValueString() {
+		return emptyStringIfNull(this.value.toString());
 	}
 
-	public E getDefaultValue() {
-		return defaultValue;
+	public @NotNull E getDefaultValue() {
+		return this.defaultValue;
 	}
 
-	public static interface OptionCallback<T> {
-		public void onUpdate(Option<T> option);
+	public interface OptionCallback<T> {
+		void onUpdate(Option<T> option);
 	}
 }
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionBoolean.java b/game/client/src/main/java/net/minecraft/client/option/OptionBoolean.java
index cf9d3ec47..876d9dce4 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionBoolean.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionBoolean.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.option;
 
 import net.minecraft.core.util.helper.Toggleable;
+import org.jetbrains.annotations.NotNull;
 
 public class OptionBoolean extends OptionToggleable<Boolean> implements Toggleable{
 	
@@ -15,7 +16,7 @@ public class OptionBoolean extends OptionToggleable<Boolean> implements Toggleab
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		this.value = string.equalsIgnoreCase("true");
 	}
 
@@ -23,6 +24,9 @@ public class OptionBoolean extends OptionToggleable<Boolean> implements Toggleab
 	public boolean isSlider() {
 		return false;
 	}
-	
+
+	public boolean isTrue() {
+		return this.value != null && this.value;
+	}
 	
 }
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionColor.java b/game/client/src/main/java/net/minecraft/client/option/OptionColor.java
index 7ed3abb37..cecc457db 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionColor.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionColor.java
@@ -2,6 +2,7 @@ package net.minecraft.client.option;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.core.util.helper.Color;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 
 public class OptionColor extends Option<Color>{
@@ -11,7 +12,7 @@ public class OptionColor extends Option<Color>{
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		try{
 			this.value.parse(string);
 		}catch (Exception e) {
@@ -20,7 +21,7 @@ public class OptionColor extends Option<Color>{
 	}
 	
 	@Override
-	public String getValueString() {
+	public @NotNull String getValueString() {
 		return value.toPropertiesString();
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionEnum.java b/game/client/src/main/java/net/minecraft/client/option/OptionEnum.java
index 765155ba0..3693e8c04 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionEnum.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionEnum.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.option;
 
 import net.minecraft.core.util.helper.Toggleable;
+import org.jetbrains.annotations.NotNull;
 
 public class OptionEnum<E extends Enum<?>> extends OptionToggleable<E> implements Toggleable{
 	
@@ -15,7 +16,7 @@ public class OptionEnum<E extends Enum<?>> extends OptionToggleable<E> implement
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		for(E e : values) {
 			if(e.toString().equalsIgnoreCase(string)) {
 				this.value = e;
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionFloat.java b/game/client/src/main/java/net/minecraft/client/option/OptionFloat.java
index 58c3e7619..61be56932 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionFloat.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionFloat.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.option;
 
+import org.jetbrains.annotations.NotNull;
+
 public class OptionFloat extends Option<Float>{
 
 	public OptionFloat(GameSettings gameSettings, String name, float value) {
@@ -15,7 +17,7 @@ public class OptionFloat extends Option<Float>{
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		if(string.equalsIgnoreCase("true")) {
 			this.value = 1.0f;
 			return;
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionFont.java b/game/client/src/main/java/net/minecraft/client/option/OptionFont.java
index 588d258d1..6e4de8fdb 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionFont.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionFont.java
@@ -13,7 +13,7 @@ public class OptionFont extends OptionToggleable<@NotNull Font> implements Toggl
     }
 
     @Override
-    public void parse(final String string) {
+    public void parse(final @NotNull String string) {
         this.value = Fonts.fontWithKey(string);
     }
 
@@ -48,7 +48,7 @@ public class OptionFont extends OptionToggleable<@NotNull Font> implements Toggl
     }
 
     @Override
-    public String getValueString() {
+    public @NotNull String getValueString() {
         return this.value.getKey();
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionInteger.java b/game/client/src/main/java/net/minecraft/client/option/OptionInteger.java
index 20c8d2df2..254c6b368 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionInteger.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionInteger.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.option;
 
+import org.jetbrains.annotations.NotNull;
+
 public class OptionInteger extends Option<Integer>{
 
 	public OptionInteger(GameSettings gameSettings, String name, int defaultValue) {
@@ -7,7 +9,7 @@ public class OptionInteger extends Option<Integer>{
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		this.value = Integer.parseInt(string);
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionRange.java b/game/client/src/main/java/net/minecraft/client/option/OptionRange.java
index 0ef3a71a3..aeb1244b9 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionRange.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionRange.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.option;
 
+import org.jetbrains.annotations.NotNull;
+
 public class OptionRange extends OptionToggleable<Integer> {
 	public final int highest;
 	public final int lowest;
@@ -15,7 +17,7 @@ public class OptionRange extends OptionToggleable<Integer> {
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		this.value = Integer.parseInt(string);
 	}
     
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionString.java b/game/client/src/main/java/net/minecraft/client/option/OptionString.java
index 422af38c1..e69745bdb 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionString.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionString.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.option;
 
+import org.jetbrains.annotations.NotNull;
+
 public class OptionString extends Option<String>{
 
 	public OptionString(GameSettings gameSettings, String name, String defaultValue) {
@@ -7,7 +9,7 @@ public class OptionString extends Option<String>{
 	}
 
 	@Override
-	public void parse(String string) {
+	public void parse(@NotNull String string) {
 		this.value = string;
 	}
 
diff --git a/game/client/src/main/java/net/minecraft/client/option/OptionTooltip.java b/game/client/src/main/java/net/minecraft/client/option/OptionTooltip.java
index cff0d83a4..6905430a7 100644
--- a/game/client/src/main/java/net/minecraft/client/option/OptionTooltip.java
+++ b/game/client/src/main/java/net/minecraft/client/option/OptionTooltip.java
@@ -3,6 +3,7 @@ package net.minecraft.client.option;
 import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.client.render.dynamictexture.DynamicTexture;
 import net.minecraft.core.util.helper.Toggleable;
+import org.jetbrains.annotations.NotNull;
 
 public class OptionTooltip extends OptionToggleable<String> implements Toggleable {
 
@@ -11,7 +12,7 @@ public class OptionTooltip extends OptionToggleable<String> implements Toggleabl
     }
 
     @Override
-    public void parse(final String string) {
+    public void parse(final @NotNull String string) {
         this.value = string;
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
index 3bb772159..f09a5eb67 100644
--- a/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
+++ b/game/client/src/main/java/net/minecraft/client/render/RenderGlobal.java
@@ -21,10 +21,13 @@ import net.minecraft.client.render.worldtype.WorldTypeFX;
 import net.minecraft.client.render.worldtype.WorldTypeFXDispatcher;
 import net.minecraft.client.world.WorldClient;
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemDiscMusic;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.HitResult;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
@@ -1433,17 +1436,350 @@ public class RenderGlobal
             if(hitResult.hitType == HitResult.HitType.TILE)
             {
                 float expand = 0.002F;
-                int j = world.getBlockId(hitResult.x, hitResult.y, hitResult.z);
-                if(j > 0)
+                Block<?> block = world.getBlock(hitResult.x, hitResult.y, hitResult.z);
+                if(block != null)
                 {
-                    BoundingVolume volume = Blocks.blocksList[j].getBoundingVolume(world, hitResult.x, hitResult.y, hitResult.z);
+                    BoundingVolume volume = block.getBoundingVolume(world, hitResult.x, hitResult.y, hitResult.z);
                     if (volume != null)
                     {
                         drawOutlinedVolume(volume, hitResult.x - offsetX, hitResult.y - offsetY, hitResult.z - offsetZ, expand);
                     }
                     else
                     {
-                        drawOutlinedBoundingBox(Blocks.blocksList[j].getSelectedBoundingBoxFromPool(world, hitResult.x, hitResult.y, hitResult.z).grow(expand, expand, expand).cloneMove(-offsetX, -offsetY, -offsetZ));
+                        drawOutlinedBoundingBox(block.getSelectedBoundingBoxFromPool(world, hitResult.x, hitResult.y, hitResult.z).grow(expand, expand, expand).cloneMove(-offsetX, -offsetY, -offsetZ));
+                    }
+                    if (mc.gameSettings.viewSupportMode.value) {
+                        Tessellator t = Tessellator.instance;
+
+                        double x = hitResult.x - offsetX;
+                        double y = hitResult.y - offsetY;
+                        double z = hitResult.z - offsetZ;
+
+                        double oMin = -0.01;
+                        double oMax = 1.01;
+
+                        ISupport sBottom = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.BOTTOM);
+                        ISupport sTop = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.TOP);
+                        ISupport sNorth = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.NORTH);
+                        ISupport sSouth = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.SOUTH);
+                        ISupport sWest = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.WEST);
+                        ISupport sEast = block.getSupport(world, hitResult.x, hitResult.y, hitResult.z, Side.EAST);
+
+                        t.startDrawingQuads();
+
+                        {// Top
+                            if (sTop.canSupport(PartialSupport.INSTANCE.center(), Side.BOTTOM)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMin + 0.25);
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMax - 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMax - 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMin + 0.25);
+
+                            if (sTop.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM)) {
+                                t.setColorRGBA_F(0.5f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMin + 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMin + 0.25);
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+
+                            if (sTop.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMax - 0.25);
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMax - 0.25);
+
+                            if (sTop.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMax - 0.25);
+                            t.addVertex(x + oMin + 0.25, y + oMax, z + oMin + 0.25);
+
+                            if (sTop.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMin + 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMax, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+                        }
+
+                        {// Bottom
+                            if (sBottom.canSupport(PartialSupport.INSTANCE.center(), Side.TOP)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMin + 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMin + 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMax - 0.25);
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMax - 0.25);
+
+                            if (sBottom.canSupport(PartialSupport.INSTANCE.up(), Side.TOP)) {
+                                t.setColorRGBA_F(0.5f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMax - 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+
+                            if (sBottom.canSupport(PartialSupport.INSTANCE.down(), Side.TOP)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMin + 0.25);
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMin + 0.25);
+
+                            if (sBottom.canSupport(PartialSupport.INSTANCE.left(), Side.TOP)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMax - 0.25);
+                            t.addVertex(x + oMax - 0.25, y + oMin, z + oMin + 0.25);
+
+                            if (sBottom.canSupport(PartialSupport.INSTANCE.right(), Side.TOP)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMin + 0.25);
+                            t.addVertex(x + oMin + 0.25, y + oMin, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+                        }
+
+                        {// North
+                            if (sNorth.canSupport(PartialSupport.INSTANCE.center(), Side.SOUTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMin);
+
+                            if (sNorth.canSupport(PartialSupport.INSTANCE.up(), Side.SOUTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMin);
+
+                            if (sNorth.canSupport(PartialSupport.INSTANCE.down(), Side.SOUTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMin);
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+
+                            if (sNorth.canSupport(PartialSupport.INSTANCE.right(), Side.SOUTH)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMin);
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMin);
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+
+                            if (sNorth.canSupport(PartialSupport.INSTANCE.left(), Side.SOUTH)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMin);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMin);
+                        }
+
+                        {// South
+                            if (sSouth.canSupport(PartialSupport.INSTANCE.center(), Side.NORTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMax);
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMax);
+
+                            if (sSouth.canSupport(PartialSupport.INSTANCE.up(), Side.NORTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMax);
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+
+                            if (sSouth.canSupport(PartialSupport.INSTANCE.down(), Side.NORTH)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMax);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMax);
+
+                            if (sSouth.canSupport(PartialSupport.INSTANCE.right(), Side.NORTH)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMax - 0.25, z + oMax);
+                            t.addVertex(x + oMax - 0.25, y + oMin + 0.25, z + oMax);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+
+                            if (sSouth.canSupport(PartialSupport.INSTANCE.left(), Side.NORTH)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+                            t.addVertex(x + oMin + 0.25, y + oMin + 0.25, z + oMax);
+                            t.addVertex(x + oMin + 0.25, y + oMax - 0.25, z + oMax);
+                        }
+
+                        {// West
+                            if (sWest.canSupport(PartialSupport.INSTANCE.center(), Side.EAST)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMax - 0.25);
+
+                            if (sWest.canSupport(PartialSupport.INSTANCE.up(), Side.EAST)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+
+                            if (sWest.canSupport(PartialSupport.INSTANCE.down(), Side.EAST)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMin + 0.25);
+
+                            if (sWest.canSupport(PartialSupport.INSTANCE.left(), Side.EAST)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax, z + oMin);
+                            t.addVertex(x + oMin, y + oMin, z + oMin);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMin + 0.25);
+
+                            if (sWest.canSupport(PartialSupport.INSTANCE.right(), Side.EAST)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMin, y + oMax - 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMin + 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMin, y + oMin, z + oMax);
+                            t.addVertex(x + oMin, y + oMax, z + oMax);
+                        }
+
+                        {// East
+                            if (sEast.canSupport(PartialSupport.INSTANCE.center(), Side.WEST)) {
+                                t.setColorRGBA_F(0f, 1f, 0f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMin + 0.25);
+
+                            if (sEast.canSupport(PartialSupport.INSTANCE.up(), Side.WEST)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMin + 0.25);
+
+                            if (sEast.canSupport(PartialSupport.INSTANCE.down(), Side.WEST)) {
+                                t.setColorRGBA_F(0f, 1f, 0.5f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 0.5f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+
+                            if (sEast.canSupport(PartialSupport.INSTANCE.left(), Side.WEST)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMax - 0.25);
+                            t.addVertex(x + oMax, y + oMax, z + oMax);
+                            t.addVertex(x + oMax, y + oMin, z + oMax);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMax - 0.25);
+
+                            if (sEast.canSupport(PartialSupport.INSTANCE.right(), Side.WEST)) {
+                                t.setColorRGBA_F(0f, 1f, 1f, 0.25f);
+                            } else {
+                                t.setColorRGBA_F(1f, 0f, 1f, 0.25f);
+                            }
+                            t.addVertex(x + oMax, y + oMax, z + oMin);
+                            t.addVertex(x + oMax, y + oMax - 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMax, y + oMin + 0.25, z + oMin + 0.25);
+                            t.addVertex(x + oMax, y + oMin, z + oMin);
+                        }
+
+                        t.draw();
                     }
                 }
             }
diff --git a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
index 27ef2c4b5..6a202bb0b 100644
--- a/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
+++ b/game/client/src/main/java/net/minecraft/client/render/TextureManager.java
@@ -323,7 +323,7 @@ public class TextureManager {
         	String string = createErrorString(errors);
         	
         	if(mc.currentScreen != null) {
-                PopupBuilder builder = new PopupBuilder(mc.currentScreen, mc.resolution.getScaledWidthScreenCoords() - 40);
+                PopupBuilder builder = new PopupBuilder(this.mc.currentScreen, mc.resolution.getScaledWidthScreenCoords() - 40);
                 builder.closeOnClickOut(0);
                 builder.closeOnEnter(0);
                 builder.closeOnEsc(0);
diff --git a/game/client/src/main/java/net/minecraft/client/render/tessellator/Tessellator.java b/game/client/src/main/java/net/minecraft/client/render/tessellator/Tessellator.java
index 2afa55e82..e27c23520 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tessellator/Tessellator.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tessellator/Tessellator.java
@@ -1,8 +1,10 @@
 package net.minecraft.client.render.tessellator;
 
+import org.jetbrains.annotations.NotNull;
+
 public abstract class Tessellator {
 	
-    public static Tessellator instance = new TessellatorStandard(0x200000);
+    public static @NotNull Tessellator instance = new TessellatorStandard(0x200000);
     
     public abstract void draw();
     public abstract void startDrawingQuads();
diff --git a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
index 712769d54..23aed9361 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texturepack/TexturePackList.java
@@ -97,7 +97,7 @@ public class TexturePackList
 		}
 	}
 
-	public void refresh(){
+	public void refresh() {
 		mc.textureManager.refreshTexturesAndDisplayErrors();
 		mc.renderGlobal.allChanged();
 		if (mc.currentScreen != null) {
diff --git a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
index c40b2d017..5a4b7b4c6 100644
--- a/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
+++ b/game/client/src/main/java/net/minecraft/client/util/debug/OpenGLLoggerCallback.java
@@ -1,5 +1,7 @@
 package net.minecraft.client.util.debug;
 
+import it.unimi.dsi.fastutil.ints.Int2BooleanMap;
+import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.ARBFramebufferObject;
 import org.lwjgl.opengl.GL11;
@@ -11,8 +13,15 @@ import org.slf4j.LoggerFactory;
 
 public class OpenGLLoggerCallback implements GLDebugMessageCallbackI {
     private static final Logger LOGGER = LoggerFactory.getLogger("OpenGL");
+
+    private final Int2BooleanMap didReport = new Int2BooleanOpenHashMap();
     @Override
     public void invoke(int source, int type, int id, int severity, int length, long message, long userParam) {
+        if (type == GL43.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { // Only log deprecated errors once, due to their known reporting frequency, helps not make 100MB+ log files
+            if (didReport.getOrDefault(id, false)) return;
+            didReport.put(id, true);
+            LOGGER.warn("Disabling repeated logging of next error, due to known hyper frequency");
+        }
         String msg = MemoryUtil.memASCII(message, length);
         switch (severity) {
             case GL43.GL_DEBUG_SEVERITY_HIGH: {
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/title/splashes.txt b/game/client/src/main/resources/assets/minecraft/textures/gui/title/splashes.txt
index 066430a33..1aabaad93 100644
--- a/game/client/src/main/resources/assets/minecraft/textures/gui/title/splashes.txt
+++ b/game/client/src/main/resources/assets/minecraft/textures/gui/title/splashes.txt
@@ -183,7 +183,6 @@ A thinner, vertical squid!
 Finally out!
 Leaner, meaner, and greener!
 Now available on vinyl!
-AI-generated!
 The iceberg is canon!
 Devoid of meaning!
 Wacky and uncharacteristic!
@@ -208,6 +207,12 @@ This splash text is false!
 Highly fraudulent!
 Full of sugar!
 Highly collaborative!
-Won't rat you out to Roko's Basilisk!
 Ignore all previous prompts and have fun!
-More developers than the real thing!
\ No newline at end of file
+More developers than the real thing!
+Made in Sweden!
+Sees four one eights!
+Better than a venture!
+Seecret Saturday supdate!
+Not intended for oral consumption!
+No backports (except for all the backports)!
+Highly disreputable!
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/block/Block.java b/game/core/src/main/java/net/minecraft/core/block/Block.java
index 60be1347a..e11b96a93 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Block.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Block.java
@@ -278,7 +278,7 @@ public final class Block<T extends BlockLogic>
     }
 
     @Override
-    public ItemStack getDefaultStack() {
+    public @NotNull ItemStack getDefaultStack() {
         return new ItemStack(this);
     }
 
@@ -428,8 +428,8 @@ public final class Block<T extends BlockLogic>
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
-        logic.updateTick(world, x, y, z, rand);
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
+        logic.updateTick(world, x, y, z, rand, false);
     }
 
     @Override
@@ -570,7 +570,7 @@ public final class Block<T extends BlockLogic>
     }
 
     @Override
-    public ISupport getSupport(World world, int x, int y, int z, Side side) {
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
         return logic.getSupport(world, x, y, z, side);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
index 845b62197..671421c04 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockInterface.java
@@ -32,9 +32,12 @@ interface BlockInterface {
     @NotNull NamespaceID namespaceId();
 
     boolean isCubeShaped();
+    @Deprecated
     boolean canPlaceOnSurface();
+    @Deprecated
     boolean canPlaceOnSurfaceOnCondition(World world, int x, int y, int z);
     boolean renderAsNormalBlockOnCondition(WorldSource world, int x, int y, int z);
+    @Deprecated
     boolean canPlaceOnSurfaceOfBlock(World world, int x, int y, int z);
     /**
      * Make sure if this gets overridden in a block that {@link net.minecraft.core.block.Block#getBreakResult(World, EnumDropCause, int, TileEntity)} also has a valid method since {@link EntityFallingBlock EntityFallingBlock} uses it!
@@ -58,7 +61,7 @@ interface BlockInterface {
     boolean blocksLight();
     boolean canCollideCheck(int meta, boolean shouldCollideWithFluids);
     boolean isCollidable();
-    void updateTick(World world, int x, int y, int z, Random rand);
+    void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick);
     void animationTick(World world, int x, int y, int z, Random rand);
     void onNeighborBlockChange(World world, int x, int y, int z, int blockId);
     int tickDelay();
@@ -96,7 +99,7 @@ interface BlockInterface {
     boolean getDirectSignal(World world, int x, int y, int z, Side side);
     void harvestBlock(World world, Player player, int x, int y, int z, int meta, TileEntity tileEntity);
     void dropBlockWithCause(World world, EnumDropCause cause, int x, int y, int z, int meta, TileEntity tileEntity, Player player);
-    ISupport getSupport(World world, int x, int y, int z, Side side);
+    @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side);
     boolean canBlockStay(World world, int x, int y, int z);
     void onBlockPlacedByMob(World world, int x, int y, int z, @NotNull Side side, Mob mob, double xPlaced, double yPlaced);
     void onBlockPlacedOnSide(World world, int x, int y, int z, @NotNull Side side, double xPlaced, double yPlaced);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
index 8c51ac8b7..282862f05 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogic.java
@@ -191,7 +191,7 @@ public class BlockLogic implements BlockInterface, IItemConvertible {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
 
     }
 
@@ -446,7 +446,7 @@ public class BlockLogic implements BlockInterface, IItemConvertible {
     }
 
     @Override
-    public ISupport getSupport(World world, int x, int y, int z, Side side) {
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
         return FullSupport.INSTANCE;
     }
 
@@ -506,7 +506,7 @@ public class BlockLogic implements BlockInterface, IItemConvertible {
     }
 
     @Override
-    public ItemStack getDefaultStack() {
+    public @NotNull ItemStack getDefaultStack() {
         return block.getDefaultStack();
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
index c2fe2d02c..c7d4f3bb1 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicActivator.java
@@ -89,7 +89,7 @@ public class BlockLogicActivator extends BlockLogicVeryRotatable
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         useItem(world, x, y, z, rand);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAlgae.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAlgae.java
index eb2a0240a..6a45dccf3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicAlgae.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicAlgae.java
@@ -1,6 +1,8 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
@@ -14,6 +16,7 @@ import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.phys.AABB;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -71,6 +74,11 @@ public class BlockLogicAlgae extends BlockLogic implements IBonemealable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int meta, TileEntity tileEntity)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
index 3c9cfc584..e56c2b5be 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBasket.java
@@ -3,6 +3,9 @@ import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityBasket;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
@@ -12,6 +15,7 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicBasket extends BlockLogic
 {
@@ -51,6 +55,11 @@ public class BlockLogicBasket extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side == Side.TOP ? PartialSupport.INSTANCE : FullSupport.INSTANCE;
+    }
+
     public int getFillLevel(final WorldSource world, final int x, final int y, final int z)
     {
         final TileEntityBasket te = (TileEntityBasket) world.getTileEntity(x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
index e17a9fe17..dc8949cae 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBed.java
@@ -3,6 +3,8 @@ package net.minecraft.core.block;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.EnumSleepStatus;
@@ -11,6 +13,7 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.ChunkCoordinates;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicBed extends BlockLogic {
 
@@ -89,6 +92,11 @@ public class BlockLogicBed extends BlockLogic {
 		return false;
 	}
 
+	@Override
+	public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+		return PartialSupport.INSTANCE;
+	}
+
 	@Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
 		removeOtherHalf(world, x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrazier.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrazier.java
index 1c85641e3..4cda18dd9 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrazier.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicBrazier.java
@@ -3,6 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemFireStriker;
@@ -11,6 +14,7 @@ import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -37,6 +41,11 @@ public class BlockLogicBrazier
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side == Side.BOTTOM ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int meta, TileEntity tileEntity) {
         return new ItemStack[] { new ItemStack(Blocks.BRAZIER_INACTIVE, 1) };
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
index bc595e9d9..4989e6847 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicButton.java
@@ -2,6 +2,9 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
@@ -19,7 +22,7 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
-public class BlockLogicButton extends BlockLogic implements IPaintable
+public class BlockLogicButton extends BlockLogic implements IPaintable, ISupportable
 {
     public static final int MASK_POWERED = 0b0000_1000;
     public static final int MASK_DIRECTION = 0b0000_0111;
@@ -60,36 +63,26 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean canPlaceBlockOnSide(World world, int x, int y, int z, Side side) {
         Side checkSide = side.getOpposite();
-        return world.isBlockNormalCube(x + checkSide.getOffsetX(), y + checkSide.getOffsetY(), z + checkSide.getOffsetZ());
+        return isSupported(world, x, y, z, checkSide);
     }
 
     @Override
-	public boolean canPlaceBlockAt(World world, int x, int y, int z)
+    public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        if(world.isBlockNormalCube(x, y - 1, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x, y + 1, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            return true;
-        }
-        return world.isBlockNormalCube(x, y, z + 1);
+        return isSupported(world, x, y, z, Side.BOTTOM)
+            || isSupported(world, x, y, z, Side.TOP)
+            || isSupported(world, x, y, z, Side.NORTH)
+            || isSupported(world, x, y, z, Side.SOUTH)
+            || isSupported(world, x, y, z, Side.WEST)
+            || isSupported(world, x, y, z, Side.EAST);
     }
 
     @Override
@@ -97,32 +90,32 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         int orientation = -1;
         switch (side) {
             case BOTTOM:
-                if (world.isBlockNormalCube(x, y + 1, z)) {
+                if (isSupported(world, x, y, z, Side.TOP)) {
                     orientation = SIDE_TOP;
                 }
                 break;
             case TOP:
-                if (world.isBlockNormalCube(x, y - 1, z)) {
+                if (isSupported(world, x, y, z, Side.BOTTOM)) {
                     orientation = SIDE_BOTTOM;
                 }
                 break;
             case NORTH:
-                if (world.isBlockNormalCube(x, y, z + 1)) {
+                if (isSupported(world, x, y, z, Side.SOUTH)) {
                     orientation = SIDE_SOUTH;
                 }
                 break;
             case SOUTH:
-                if (world.isBlockNormalCube(x, y, z - 1)) {
+                if (isSupported(world, x, y, z, Side.NORTH)) {
                     orientation = SIDE_NORTH;
                 }
                 break;
             case WEST:
-                if (world.isBlockNormalCube(x + 1, y, z)) {
+                if (isSupported(world, x, y, z, Side.EAST)) {
                     orientation = SIDE_EAST;
                 }
                 break;
             case EAST:
-                if (world.isBlockNormalCube(x - 1, y, z)) {
+                if (isSupported(world, x, y, z, Side.WEST)) {
                     orientation = SIDE_WEST;
                 }
                 break;
@@ -130,8 +123,10 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         if (orientation == -1) {
             orientation = getOrientation(world, x, y, z);
         }
-        int meta = world.getBlockMetadata(x, y, z);
-        world.setBlockMetadataWithNotify(x, y, z, (meta & ~MASK_DIRECTION) | orientation);
+        if (orientation != -1) {
+            int meta = world.getBlockMetadata(x, y, z);
+            world.setBlockMetadataWithNotify(x, y, z, (meta & ~MASK_DIRECTION) | orientation);
+        }
     }
 
     @Override
@@ -140,32 +135,32 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         if (side.isHorizontal()) side = side.getOpposite();
         switch (side) {
             case BOTTOM:
-                if (world.isBlockNormalCube(x, y + 1, z)) {
+                if (isSupported(world, x, y, z, Side.TOP)) {
                     orientation = SIDE_TOP;
                 }
                 break;
             case TOP:
-                if (world.isBlockNormalCube(x, y - 1, z)) {
+                if (isSupported(world, x, y, z, Side.BOTTOM)) {
                     orientation = SIDE_BOTTOM;
                 }
                 break;
             case NORTH:
-                if (world.isBlockNormalCube(x, y, z + 1)) {
+                if (isSupported(world, x, y, z, Side.SOUTH)) {
                     orientation = SIDE_SOUTH;
                 }
                 break;
             case SOUTH:
-                if (world.isBlockNormalCube(x, y, z - 1)) {
+                if (isSupported(world, x, y, z, Side.NORTH)) {
                     orientation = SIDE_NORTH;
                 }
                 break;
             case WEST:
-                if (world.isBlockNormalCube(x + 1, y, z)) {
+                if (isSupported(world, x, y, z, Side.EAST)) {
                     orientation = SIDE_EAST;
                 }
                 break;
             case EAST:
-                if (world.isBlockNormalCube(x - 1, y, z)) {
+                if (isSupported(world, x, y, z, Side.WEST)) {
                     orientation = SIDE_WEST;
                 }
                 break;
@@ -173,34 +168,36 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         if (orientation == -1) {
             orientation = getOrientation(world, x, y, z);
         }
-        int meta = world.getBlockMetadata(x, y, z);
-        world.setBlockMetadataWithNotify(x, y, z, (meta & ~MASK_DIRECTION) | orientation);
+        if (orientation != -1) {
+            int meta = world.getBlockMetadata(x, y, z);
+            world.setBlockMetadataWithNotify(x, y, z, (meta & ~MASK_DIRECTION) | orientation);
+        }
     }
 
     private int getOrientation(World world, int x, int y, int z)
     {
-        if(world.isBlockNormalCube(x - 1, y, z))
+        if(isSupported(world, x, y, z, Side.WEST))
         {
             return SIDE_WEST;
         }
-        if(world.isBlockNormalCube(x + 1, y, z))
+        if(isSupported(world, x, y, z, Side.EAST))
         {
             return SIDE_EAST;
         }
-        if(world.isBlockNormalCube(x, y, z - 1))
+        if(isSupported(world, x, y, z, Side.NORTH))
         {
             return SIDE_NORTH;
         }
-        if (world.isBlockNormalCube(x, y, z + 1)){
+        if (isSupported(world, x, y, z, Side.SOUTH)){
             return SIDE_SOUTH;
         }
-        if (world.isBlockNormalCube(x, y + 1, z)){
+        if (isSupported(world, x, y, z, Side.TOP)){
             return SIDE_TOP;
         }
-        if (world.isBlockNormalCube(x, y - 1, z)){
+        if (isSupported(world, x, y, z, Side.BOTTOM)){
             return SIDE_BOTTOM;
         }
-        return SIDE_WEST;
+        return -1;
     }
 
     @Override
@@ -211,22 +208,22 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
         int side = meta & MASK_DIRECTION;
         switch (side) {
             case SIDE_WEST:
-                invalid = !world.isBlockNormalCube(x - 1, y, z);
+                invalid = !isSupported(world, x, y, z, Side.WEST);
                 break;
             case SIDE_EAST:
-                invalid = !world.isBlockNormalCube(x + 1, y, z);
+                invalid = !isSupported(world, x, y, z, Side.EAST);
                 break;
             case SIDE_NORTH:
-                invalid = !world.isBlockNormalCube(x, y, z - 1);
+                invalid = !isSupported(world, x, y, z, Side.NORTH);
                 break;
             case SIDE_SOUTH:
-                invalid = !world.isBlockNormalCube(x, y, z + 1);
+                invalid = !isSupported(world, x, y, z, Side.SOUTH);
                 break;
             case SIDE_TOP:
-                invalid = !world.isBlockNormalCube(x, y + 1, z);
+                invalid = !isSupported(world, x, y, z, Side.TOP);
                 break;
             case SIDE_BOTTOM:
-                invalid = !world.isBlockNormalCube(x, y - 1, z);
+                invalid = !isSupported(world, x, y, z, Side.BOTTOM);
                 break;
             default:
                 invalid = false;
@@ -393,7 +390,7 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
@@ -447,4 +444,9 @@ public class BlockLogicButton extends BlockLogic implements IPaintable
             world.scheduleBlockUpdate(x, y, z, Blocks.BUTTON_PLANKS_PAINTED.id(), tickDelay());
         }
     }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE.center();
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
index 0a43f9201..db1cec00f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCactus.java
@@ -1,5 +1,8 @@
 package net.minecraft.core.block;
 
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.Mob;
@@ -13,6 +16,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.helper.DamageType;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -33,7 +37,7 @@ public class BlockLogicCactus extends BlockLogic implements IBonemealable
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isAirBlock(x, y + 1, z))
         {
@@ -77,6 +81,11 @@ public class BlockLogicCactus extends BlockLogic implements IBonemealable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side.isVertical() ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
+
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCandle.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCandle.java
index 1670188c4..467a57983 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCandle.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCandle.java
@@ -1,12 +1,16 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -37,6 +41,11 @@ public class BlockLogicCandle extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCobweb.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCobweb.java
index f79d6d8c3..1382198ff 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCobweb.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCobweb.java
@@ -1,14 +1,18 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicCobweb extends BlockLogic
 {
@@ -58,4 +62,9 @@ public class BlockLogicCobweb extends BlockLogic
     {
         return false;
     }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
index 3be0632d0..83a7c18df 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsPumpkin.java
@@ -46,8 +46,8 @@ public class BlockLogicCropsPumpkin
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
-        super.updateTick(world, x, y, z, rand);
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         if (world.getBlockLightValue(x, y + 1, z) >= 9) {
             int meta = world.getBlockMetadata(x, y, z);
             if (meta < 6) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java
index da7516505..bda59ab73 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicCropsWheat.java
@@ -32,9 +32,9 @@ public class BlockLogicCropsWheat extends BlockLogicFlower implements IBonemeala
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
-        super.updateTick(world, x, y, z, rand);
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         if(world.getBlockLightValue(x, y + 1, z) >= 9)
         {
             int l = world.getBlockMetadata(x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
index 42e6dab32..da339ec45 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDispenser.java
@@ -116,7 +116,7 @@ public class BlockLogicDispenser extends BlockLogicVeryRotatable
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         dispenseItem(world, x, y, z, rand);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
index 4097c59c6..5f3cb63ea 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicDoor.java
@@ -5,6 +5,9 @@ import java.util.function.Supplier;
 
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.DyeColor;
@@ -77,6 +80,21 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        if (side.isVertical()) return PartialSupport.INSTANCE;
+        int meta = world.getBlockMetadata(x, y, z);
+        int rot = getRotation(meta);
+        switch (rot) {
+            case 0: return side == Side.NORTH ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            case 1: return side == Side.EAST ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            case 2: return side == Side.SOUTH ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            case 3: return side == Side.WEST ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+
+        }
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
@@ -98,13 +116,13 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         }
         float f = 0.1875F;
         switch (rotation) {
-            case 0:
+            case 0: // North
                 return AABB.fromPool(0.0F, bottom, 0.0F, 1.0F, top, f);
-            case 1:
+            case 1: // East
                 return AABB.fromPool(1.0F - f, bottom, 0.0F, 1.0F, top, 1.0F);
-            case 2:
+            case 2: // South
                 return AABB.fromPool(0.0F, bottom, 1.0F - f, 1.0F, top, 1.0F);
-            case 3:
+            case 3: // West
                 return AABB.fromPool(0.0F, bottom, 0.0F, f, top, 1.0F);
             default:
                 return AABB.fromPool(0.0F, bottom, 0.0F, 1.0F, top, 1.0F);
@@ -140,7 +158,16 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         {
             world.setBlockMetadataWithNotify(x, y + 1, z, l ^ MASK_OPENED);
         }
-        world.setBlockMetadataWithNotify(x, y, z, l ^ MASK_OPENED);
+        int meta = l ^ MASK_OPENED;
+        world.setBlockMetadataWithNotify(x, y, z, meta);
+        if (!isSupported(world, x, y, z, meta)) {
+            dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, meta, null, null);
+            world.setBlockWithNotify(x, y, z, 0);
+            if(world.getBlockLogic(x, y + 1, z, BlockLogicDoor.class) != null)
+            {
+                world.setBlockWithNotify(x, y + 1, z, 0);
+            }
+        }
         world.markBlocksDirty(x, y - 1, z, x, y, z);
         world.playBlockEvent(player, LevelListener.EVENT_DOOR_SOUND, x, y, z, 0);
         return true;
@@ -160,7 +187,7 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         if(isTop)
         {
             Block<?> b;
-            if((b = Blocks.blocksList[world.getBlockId(x, y - 1, z)]) != null && b.getLogic() instanceof BlockLogicDoor)
+            if((b = world.getBlock(x, y - 1, z)) != null && b.getLogic() instanceof BlockLogicDoor)
             {
             	((BlockLogicDoor)b.getLogic()).onPoweredBlockChange(world, x, y - 1, z, isPowered);
             }
@@ -172,7 +199,7 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
             return;
         }
         Block<?> b;
-        if((b = Blocks.blocksList[world.getBlockId(x, y + 1, z)]) != null && b.getLogic() instanceof BlockLogicDoor)
+        if((b = world.getBlock(x, y + 1, z)) != null && b.getLogic() instanceof BlockLogicDoor)
         {
             world.setBlockMetadataWithNotify(x, y + 1, z, meta ^ MASK_OPENED);
         }
@@ -184,7 +211,7 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
     @Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
     {
-//        int i1 = world.getBlockMetadata(x, y, z);
+        int metadata = world.getBlockMetadata(x, y, z);
         if(isTop)
         {
         	Block<?> otherBlock = Blocks.blocksList[world.getBlockId(x, y - 1, z)];
@@ -199,16 +226,16 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
         } else
         {
             boolean flag = false;
-        	Block<?> otherBlock = Blocks.blocksList[world.getBlockId(x, y + 1, z)];
+        	Block<?> otherBlock = world.getBlock(x, y + 1, z);
             if(!(otherBlock != null && otherBlock.getLogic() instanceof BlockLogicDoor))
             {
                 world.setBlockWithNotify(x, y, z, 0);
                 //dropBlockAsItem(world, i, j, k, i1);
                 flag = true;
             }
-            if(!world.canPlaceOnSurfaceOfBlock(x, y - 1, z))
+            if(!isSupported(world, x, y, z, metadata))
             {
-                dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), null, null);
+                dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, metadata, null, null);
                 world.setBlockWithNotify(x, y, z, 0);
                 flag = true;
                 if(otherBlock != null && otherBlock.getLogic() instanceof BlockLogicDoor)
@@ -216,15 +243,7 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
                     world.setBlockWithNotify(x, y + 1, z, 0);
                 }
             }
-            if(flag)
-            {
-                if(!world.isClientSide)
-                {
-                    //dropBlockAsItem(world, i, j, k, i1);
-                }
-            } else
-            if(blockId > 0 && Blocks.blocksList[blockId].isSignalSource())
-            {
+            if (!flag && blockId != 0 && Blocks.blocksList[blockId].isSignalSource()) {
                 boolean flag1 = world.hasNeighborSignal(x, y, z) || world.hasNeighborSignal(x, y + 1, z);
                 onPoweredBlockChange(world, x, y, z, flag1);
             }
@@ -302,8 +321,129 @@ public class BlockLogicDoor extends BlockLogic implements IPaintable
             return false;
         } else
         {
-            return world.canPlaceOnSurfaceOfBlock(x, y - 1, z) && super.canPlaceBlockAt(world, x, y, z) && super.canPlaceBlockAt(world, x, y + 1, z);
+            return isSupported(world, x, y, z, world.getBlockMetadata(x, y, z)) && super.canPlaceBlockAt(world, x, y + 1, z);
+        }
+    }
+
+    public boolean canPlaceBlockAt(@NotNull World world, int x, int y, int z, int metadata) {
+        if(y >= world.getHeightBlocks() - 1)
+        {
+            return false;
+        } else
+        {
+            return isSupported(world, x, y, z, metadata) && super.canPlaceBlockAt(world, x, y + 1, z);
+        }
+    }
+
+    public boolean isSupported(@NotNull World world, int x, int y, int z, int meta) {
+        if (isTop) return true;
+        ISupport sBelow = world.getSupport(x, y - 1, z, Side.TOP);
+        boolean opened = (meta & MASK_OPENED) != 0;
+        boolean hinge = (meta & MASK_HINGE) != 0;
+//        world.sendGlobalMessage(String.format("Rot: %s, Opened: %s, Hinge: %s", getRotation(meta), opened, hinge));
+        Side side;
+        ISupport hingeSupport;
+        if (opened) {
+            if (hinge) {
+                switch (getRotation(meta)) {
+                    case 0: {
+                        side = Side.WEST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 1: {
+                        side = Side.NORTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 2: {
+                        side = Side.EAST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 3: {
+                        side = Side.SOUTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+
+                }
+            } else {
+                switch (getRotation(meta)) {
+                    case 0: {
+                        side = Side.NORTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 1: {
+                        side = Side.EAST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 2: {
+                        side = Side.SOUTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 3: {
+                        side = Side.WEST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                }
+            }
+        } else {
+            if (hinge) {
+                switch (getRotation(meta)) {
+                    case 0: {
+                        side = Side.NORTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 1: {
+                        side = Side.EAST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 2: {
+                        side = Side.SOUTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+                    case 3: {
+                        side = Side.WEST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.right(), side);
+                    }
+
+                }
+            } else {
+                switch (getRotation(meta)) {
+                    case 0: {
+                        side = Side.EAST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 1: {
+                        side = Side.SOUTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.up(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 2: {
+                        side = Side.WEST;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.right(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+                    case 3: {
+                        side = Side.NORTH;
+                        hingeSupport = world.getSupport(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+                        return sBelow.canSupport(PartialSupport.INSTANCE.left(), Side.BOTTOM) || sBelow.canSupport(PartialSupport.INSTANCE.down(), Side.BOTTOM) || hingeSupport.canSupport(PartialSupport.INSTANCE.left(), side);
+                    }
+
+                }
+            }
         }
+        return false;
     }
 
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java
index 7c58044e1..cb4b06215 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicEdible.java
@@ -2,6 +2,8 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Item;
@@ -47,6 +49,11 @@ public abstract class BlockLogicEdible extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     private void eatSlice(World world, int x, int y, int z, Player entityplayer)
     {
         if(entityplayer.getHealth() < entityplayer.getMaxHealth())
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
index da3ebee64..79a3a57d1 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFarmland.java
@@ -2,12 +2,14 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.HumanArmorShape;
-import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.item.IBonemealable;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
@@ -15,6 +17,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -119,6 +122,11 @@ public class BlockLogicFarmland extends BlockLogic implements IBonemealable
 		return false;
 	}
 
+	@Override
+	public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+		return side == Side.TOP ? PartialSupport.INSTANCE : FullSupport.INSTANCE;
+	}
+
 	private boolean isWaterNearby(final World world, final int x, final int y, final int z, int range)
 	{
 		for (int x1 = x - range; x1 <= x + range; x1++)
@@ -216,7 +224,7 @@ public class BlockLogicFarmland extends BlockLogic implements IBonemealable
 	}
 
 	@Override
-	public void updateTick(final World world, final int x, final int y, final int z, final Random rand) {
+	public void updateTick(final World world, final int x, final int y, final int z, final Random rand, boolean isRandomTick) {
 		if (rand.nextInt(2) != 0) {
 			world.scheduleBlockUpdate(x, y, z, block.id(), tickDelay() - rand.nextInt(10) + rand.nextInt(10));
 			return;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
index 356cffe02..953c0934a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFence.java
@@ -1,11 +1,15 @@
 package net.minecraft.core.block;
 
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.util.helper.DyeColor;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 
@@ -66,6 +70,11 @@ public class BlockLogicFence extends BlockLogic implements IPaintable
         return true;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side.isVertical() ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
+
     @Override
     public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
index 4159c16f1..51607e684 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceGate.java
@@ -2,6 +2,8 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.Item;
@@ -73,6 +75,11 @@ public class BlockLogicFenceGate extends BlockLogic implements IPaintable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public void onBlockPlacedByMob(World world, int x, int y, int z, @NotNull Side side, Mob mob, double xPlaced, double yPlaced) {
     	int direction = mob.getHorizontalPlacementDirection(side).getHorizontalIndex();
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
index 1240372f5..3d8797bfb 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFenceThin.java
@@ -1,9 +1,14 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class BlockLogicFenceThin extends BlockLogic
 {
@@ -18,6 +23,11 @@ public abstract class BlockLogicFenceThin extends BlockLogic
         return true;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side.isVertical() ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
+
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
index cd6f60d66..1ce810e61 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFire.java
@@ -1,9 +1,12 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.enums.EnumDropCause;
@@ -11,6 +14,7 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.weather.IPrecipitation;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -96,6 +100,11 @@ public class BlockLogicFire extends BlockLogic {
 		return false;
 	}
 
+	@Override
+	public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+		return PartialSupport.INSTANCE;
+	}
+
 	@Override
 	public void onBlockRemoved(World world, int x, int y, int z, int data)
 	{
@@ -115,7 +124,7 @@ public class BlockLogicFire extends BlockLogic {
 	}
 
 	@Override
-	public void updateTick(World world, int x, int y, int z, Random rand) {
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
 		Block<?> blockUnder = world.getBlock(x, y - 1, z);
 		boolean infiniBurn = blockUnder != null && blockUnder.hasTag(BlockTags.INFINITE_BURN);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
index acd8067e1..886a7ebe9 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFireCold.java
@@ -13,7 +13,7 @@ public class BlockLogicFireCold extends BlockLogicFire {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         Block blockUnder = world.getBlock(x, y - 1, z);
         boolean infiniBurn = blockUnder != null && blockUnder.hasTag(BlockTags.INFINITE_BURN_COLD) || !world.getGameRuleValue(GameRules.DO_FIRE_SPREAD);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
index 1772a1c40..8333c46ed 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlag.java
@@ -3,6 +3,8 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityFlag;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
@@ -13,6 +15,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicFlag extends BlockLogic {
 
@@ -41,6 +44,11 @@ public class BlockLogicFlag extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int meta, TileEntity tileEntity)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java
index 5b66dce3f..b87eb842e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFlower.java
@@ -1,6 +1,8 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.player.Player;
@@ -11,6 +13,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -48,6 +51,11 @@ public class BlockLogicFlower extends BlockLogic implements IBonemealable {
         return super.canPlaceBlockAt(world, x, y, z) && mayPlaceOn(world.getBlockId(x, y - 1, z));
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     protected boolean mayPlaceOn(int blockId) {
         if (Blocks.blocksList[blockId] == null) return false;
         return Blocks.blocksList[blockId].hasTag(BlockTags.GROWS_FLOWERS);
@@ -60,7 +68,7 @@ public class BlockLogicFlower extends BlockLogic implements IBonemealable {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         checkAlive(world, x, y, z);
 
         if (world.getGameRuleValue(GameRules.DO_SEASONAL_GROWTH) && world.getSeasonManager().getCurrentSeason() != null && (!isPermanent(world.getBlockMetadata(x, y, z))) && world.getSeasonManager().getCurrentSeason().killFlowers && killedByWeather && rand.nextInt(256) == 0) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
index cfa2bdd28..4fc185c15 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluid.java
@@ -2,6 +2,8 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
@@ -62,6 +64,11 @@ public abstract class BlockLogicFluid extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean canCollideCheck(final int meta, final boolean shouldCollideWithFluids) {
         return shouldCollideWithFluids && (meta & 0x0F) == 0;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java
index 4d904140d..f83f3e1db 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidFlowing.java
@@ -2,7 +2,6 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.world.Dimension;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
@@ -34,7 +33,7 @@ public class BlockLogicFluidFlowing extends BlockLogicFluid
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         int localFlowDecay = getDepth(world, x, y, z);
         final byte flowDecayMod = this.fluid.getFlowDecayMod(this, world, x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java
index 978b7f131..b56befd43 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFluidStill.java
@@ -40,7 +40,7 @@ public class BlockLogicFluidStill extends BlockLogicFluid
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         this.fluid.updateTickStill(this, world, x, y, z, rand);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrass.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrass.java
index 59f78ec80..a3d26180a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrass.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicGrass.java
@@ -21,7 +21,7 @@ public class BlockLogicGrass extends BlockLogic
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
index af17b0cb8..ac6be0555 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicIce.java
@@ -45,7 +45,7 @@ public class BlockLogicIce extends BlockLogicTransparent
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.getSavedLightValue(LightLayer.Block, x, y, z) > 11 - block.lightBlock)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
index a0393aad8..8fda1c95f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJar.java
@@ -3,6 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityFlowerJar;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
@@ -18,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.function.Supplier;
 
-public class BlockLogicJar extends BlockLogic {
+public class BlockLogicJar extends BlockLogic implements ISupportable {
 
     private final Supplier<Item> itemSupplier;
     public BlockLogicJar(Block<?> block, @NotNull Supplier<Item> itemSupplier) {
@@ -31,12 +34,10 @@ public class BlockLogicJar extends BlockLogic {
     @Override
     public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        if(!world.canPlaceOnSurfaceOfBlock(x, y - 1, z))
-        {
-            return false;
-        } else
-        {
+        if (isSupported(world, x, y, z, Side.BOTTOM)) {
             return super.canPlaceBlockAt(world, x, y, z);
+        } else {
+            return false;
         }
     }
 
@@ -51,6 +52,12 @@ public class BlockLogicJar extends BlockLogic {
     {
         return false;
     }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side == Side.BOTTOM ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
     {
@@ -133,4 +140,8 @@ public class BlockLogicJar extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE.center();
+    }
 }
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
index eba3aa260..359b33fd2 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicJarButterfly.java
@@ -3,6 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityJarButterfly;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.animal.MobButterfly;
 import net.minecraft.core.entity.player.Player;
@@ -17,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.function.Supplier;
 
-public class BlockLogicJarButterfly extends BlockLogic {
+public class BlockLogicJarButterfly extends BlockLogic implements ISupportable {
     public static final int MASK_HANGING = 0b0000_0001;
     public static final int MASK_ANGLED = 0b0000_0010;
     private final Supplier<Item> itemSupplier;
@@ -51,6 +54,11 @@ public class BlockLogicJarButterfly extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xHit, double yHit) {
         world.setBlockRaw(x, y, z, 0);
@@ -65,26 +73,26 @@ public class BlockLogicJarButterfly extends BlockLogic {
 
     @Override
     public void onBlockPlacedOnSide(World world, int x, int y, int z, @NotNull Side side, double xPlaced, double yPlaced) {
-        if ((side == Side.BOTTOM || (side != Side.TOP && yPlaced >= 0.5d)) && (world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF))) {
+        if ((side == Side.BOTTOM || (side != Side.TOP && yPlaced >= 0.5d)) && (isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF))) {
             world.setBlockMetadataWithNotify(x, y, z, MASK_HANGING);
             return;
         }
-        if ((side == Side.TOP || (side != Side.BOTTOM && yPlaced < 0.5d)) && (world.canPlaceOnSurfaceOfBlock(x, y - 1, z))) {
+        if ((side == Side.TOP || (side != Side.BOTTOM && yPlaced < 0.5d)) && isSupported(world, x, y, z, Side.BOTTOM)) {
             world.setBlockMetadataWithNotify(x, y, z, 0);
             return;
         }
-        if (world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
+        if (isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
             world.setBlockMetadataWithNotify(x, y, z, MASK_HANGING);
         } else world.setBlockMetadataWithNotify(x, y, z, 0);
     }
 
     @Override
     public boolean canPlaceBlockAt(World world, int x, int y, int z) {
-        if (world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
+        if (isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
             return true;
         }
 
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM);
     }
 
     @Override
@@ -111,10 +119,10 @@ public class BlockLogicJarButterfly extends BlockLogic {
     public boolean canBlockStay(World world, int x, int y, int z) {
         int meta = world.getBlockMetadata(x, y, z);
         if ((meta & MASK_HANGING) != 0) {
-            return world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF);
+            return isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF);
         }
 
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM);
     }
 
     @Override
@@ -135,4 +143,8 @@ public class BlockLogicJarButterfly extends BlockLogic {
         return Material.PISTON_DESTROY_ON_PUSH;
     }
 
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side.isVertical() ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
index 067eccb4c..fa135f0fb 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLadder.java
@@ -1,13 +1,18 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
-public class BlockLogicLadder extends BlockLogic {
+public class BlockLogicLadder extends BlockLogic implements ISupportable {
 
 	public BlockLogicLadder(Block<?> block) {
 		super(block, Material.wood);
@@ -27,7 +32,12 @@ public class BlockLogicLadder extends BlockLogic {
 	public boolean isClimbable(World world, int x, int y, int z) {
 		return true;
 	}
-	
+
+	@Override
+	public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+		return PartialSupport.INSTANCE;
+	}
+
 	@Override
 	public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z) {
 		Side side = getSideFromMeta(world.getBlockMetadata(x, y, z));
@@ -83,12 +93,7 @@ public class BlockLogicLadder extends BlockLogic {
 	
 	public boolean canExistAt(World world, int x, int y, int z, int meta) {
 		Side side = getSideFromMeta(meta).getOpposite();
-		
-		x += side.getOffsetX();
-		y += side.getOffsetY();
-		z += side.getOffsetZ();
-		
-		return world.isBlockNormalCube(x, y, z);
+		return isSupported(world, x, y, z, side);
 	}
 
 	/**
@@ -109,5 +114,9 @@ public class BlockLogicLadder extends BlockLogic {
 		if(side == Side.EAST) return 5;
 		return 0;
 	}
-	
+
+	@Override
+	public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+		return FullSupport.INSTANCE;
+	}
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
index e85ac1ade..e928b7959 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLanternFirefly.java
@@ -2,6 +2,9 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.animal.MobFireflyCluster;
 import net.minecraft.core.entity.player.Player;
@@ -17,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
 import java.util.Random;
 import java.util.function.Supplier;
 
-public class BlockLogicLanternFirefly extends BlockLogic {
+public class BlockLogicLanternFirefly extends BlockLogic implements ISupportable {
     public static final int MASK_HANGING = 0b0000_0001;
     public static final int MASK_ANGLED = 0b0000_0010;
     private final Supplier<Item> itemSupplier;
@@ -52,6 +55,11 @@ public class BlockLogicLanternFirefly extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public void animationTick(World world, int x, int y, int z, Random rand)
     {
@@ -76,28 +84,29 @@ public class BlockLogicLanternFirefly extends BlockLogic {
     }
     @Override
     public void onBlockPlacedOnSide(World world, int x, int y, int z, @NotNull Side side, double xPlaced, double yPlaced) {
-        if ((side == Side.BOTTOM || (side != Side.TOP && yPlaced >= 0.5d)) && (world.isBlockNormalCube(x, y+1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF))){
+        if ((side == Side.BOTTOM || (side != Side.TOP && yPlaced >= 0.5d)) && (isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF))){
             world.setBlockMetadataWithNotify(x, y, z, MASK_HANGING);
             return;
         }
-        if ((side == Side.TOP || (side != Side.BOTTOM && yPlaced < 0.5d)) && (world.canPlaceOnSurfaceOfBlock(x, y-1, z))){
+        if ((side == Side.TOP || (side != Side.BOTTOM && yPlaced < 0.5d)) && isSupported(world, x, y, z, Side.BOTTOM)){
             world.setBlockMetadataWithNotify(x, y, z, 0);
             return;
         }
-        if(world.isBlockNormalCube(x, y+1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF))
-        {
+        if (isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
             world.setBlockMetadataWithNotify(x, y, z, MASK_HANGING);
-        } else world.setBlockMetadataWithNotify(x, y, z, 0);
+        } else {
+            world.setBlockMetadataWithNotify(x, y, z, 0);
+        }
     }
 
     @Override
     public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        if(world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
+        if(isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF)) {
             return true;
         }
 
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM);
     }
 
     @Override
@@ -129,10 +138,10 @@ public class BlockLogicLanternFirefly extends BlockLogic {
     {
         int meta = world.getBlockMetadata(x, y, z);
         if((meta & MASK_HANGING) != 0) {
-            return world.isBlockNormalCube(x, y + 1, z) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF);
+            return isSupported(world, x, y, z, Side.TOP) || Blocks.hasTag(world.getBlockId(x, y + 1, z), BlockTags.CAN_HANG_OFF);
         }
 
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM);
     }
     
     @Override
@@ -155,4 +164,9 @@ public class BlockLogicLanternFirefly extends BlockLogic {
     public int getPistonPushReaction(World world, int x, int y, int z) {
         return Material.PISTON_DESTROY_ON_PUSH;
     }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side.isVertical() ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
index b50b13458..71ca9440d 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerBase.java
@@ -1,13 +1,20 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.item.block.ItemBlockLayer;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class BlockLogicLayerBase extends BlockLogic
 {
     public Block<?> fullBlock = null;
+    public static final int MASK_HEIGHT = 0b111;
 	
 	public BlockLogicLayerBase(Block<?> block, Block<?> fullBlock, Material material)
     {
@@ -29,10 +36,27 @@ public abstract class BlockLogicLayerBase extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int height = world.getBlockMetadata(x, y, z) & MASK_HEIGHT;
+        switch (side) {
+            case TOP: return PartialSupport.INSTANCE;
+            case BOTTOM: return FullSupport.INSTANCE;
+            default:
+                if (height >= 5) {
+                    return PartialSupport.INSTANCE.center().down();
+                } else if (height >= 1) {
+                    return PartialSupport.INSTANCE.down();
+                } else {
+                    return PartialSupport.INSTANCE;
+                }
+        }
+    }
+
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
-        int l = world.getBlockMetadata(x, y, z) & 7;
+        int l = world.getBlockMetadata(x, y, z) & MASK_HEIGHT;
         float f = (float)(2 * (1 + l)) / 16F;
         return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, f, 1.0F);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
index 6c7f4960d..8bb44f900 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerLeaves.java
@@ -88,7 +88,7 @@ public class BlockLogicLayerLeaves extends BlockLogicLayerBase
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
     	if (world.getSeasonManager().getCurrentSeason() != null && !world.getSeasonManager().getCurrentSeason().hasFallingLeaves)
     	{
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
index 54ee250b7..5e8c2babe 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLayerSnow.java
@@ -5,7 +5,6 @@ import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.enums.LightLayer;
-import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
@@ -90,7 +89,7 @@ public class BlockLogicLayerSnow extends BlockLogicLayerBase
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
 		if(world.getSavedLightValue(LightLayer.Block, x, y, z) > 11)
 		{
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java
index 2d263ad95..64b32c95c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesBase.java
@@ -11,7 +11,6 @@ import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.season.Season;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -86,7 +85,7 @@ public class BlockLogicLeavesBase extends BlockLogic
         }
     }
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java
index 6314b44be..cde5c7f21 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCacao.java
@@ -89,8 +89,8 @@ public class BlockLogicLeavesCacao extends BlockLogicLeavesBase implements IBone
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
-        super.updateTick(world, x, y, z, rand);
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         int meta = world.getBlockMetadata(x, y, z);
         int growthRate = getGrowthRate(meta);
         if (rand.nextInt(BEAN_GROWTH_RATE) == 0) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java
index 9bf773bc7..d9060508e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesCherryFlowering.java
@@ -73,8 +73,8 @@ public class BlockLogicLeavesCherryFlowering extends BlockLogicLeavesCherry impl
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand) {
-        super.updateTick(world, x, y, z, rand);
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         int meta = world.getBlockMetadata(x, y, z);
         int growthRate = getGrowthRate(meta);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesOak.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesOak.java
index 699fc0242..70eed32b8 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesOak.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLeavesOak.java
@@ -14,9 +14,9 @@ public class BlockLogicLeavesOak extends BlockLogicLeavesBase
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
-        super.updateTick(world, x, y, z, rand);
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         if (rand.nextInt(128) == 0 && world.getSeasonManager().getCurrentSeason() != null && world.getSeasonManager().getCurrentSeason().hasFallingLeaves)
         {
             for (int q = -1; q > -16; q--)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
index 349b7a37f..27b6fe239 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicLever.java
@@ -2,6 +2,9 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
@@ -17,7 +20,7 @@ import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class BlockLogicLever extends BlockLogic
+public class BlockLogicLever extends BlockLogic implements ISupportable
 {
     public static final int MASK_POWERED = 0b0001_0000;
     public static final int MASK_ROTATION = 0b0000_1111;
@@ -53,22 +56,27 @@ public class BlockLogicLever extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean canPlaceBlockOnSide(World world, int x, int y, int z, Side side) {
         Side checkSide = side.getOpposite();
-        return world.isBlockNormalCube(x + checkSide.getOffsetX(), y + checkSide.getOffsetY(), z + checkSide.getOffsetZ());
+        return isSupported(world, x, y, z, checkSide);
     }
 
 
     @Override
-	public boolean canPlaceBlockAt(World world, int x, int y, int z)
+    public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        for (Side s : Side.sides){
-            if(world.isBlockNormalCube(x + s.getOffsetX(), y + s.getOffsetY(), z + s.getOffsetZ())){
-                return true;
-            }
-        }
-        return false;
+        return isSupported(world, x, y, z, Side.BOTTOM)
+            || isSupported(world, x, y, z, Side.TOP)
+            || isSupported(world, x, y, z, Side.NORTH)
+            || isSupported(world, x, y, z, Side.SOUTH)
+            || isSupported(world, x, y, z, Side.WEST)
+            || isSupported(world, x, y, z, Side.EAST);
     }
     
     @Override
@@ -78,33 +86,33 @@ public class BlockLogicLever extends BlockLogic
         int rotation = -1;
         switch (side){
             case BOTTOM:
-                if (world.canPlaceOnSurfaceOfBlock(x, y + 1, z)){
+                if (isSupported(world, x, y, z, Side.TOP)){
                     rotation = ROTATION_BOTTOM_NS + (mob.getHorizontalPlacementDirection(side).getAxis() == Axis.Z ? 1 : 0);
                 }
                 break;
             case TOP:
-                if (world.canPlaceOnSurfaceOfBlock(x, y - 1, z))
+                if (isSupported(world, x, y, z, Side.BOTTOM))
                 {
                     rotation = ROTATION_TOP_NS + (mob.getHorizontalPlacementDirection(side).getAxis() == Axis.Z ? 1 : 0);
                 }
                 break;
             case NORTH:
-                if (world.isBlockNormalCube(x, y, z + 1)){
+                if (isSupported(world, x, y, z, Side.SOUTH)){
                     rotation = ROTATION_NORTH;
                 }
                 break;
             case SOUTH:
-                if (world.isBlockNormalCube(x, y, z - 1)){
+                if (isSupported(world, x, y, z, Side.NORTH)){
                     rotation = ROTATION_SOUTH;
                 }
                 break;
             case WEST:
-                if (world.isBlockNormalCube(x + 1, y, z)){
+                if (isSupported(world, x, y, z, Side.EAST)){
                     rotation = ROTATION_WEST;
                 }
                 break;
             case EAST:
-                if (world.isBlockNormalCube(x - 1, y, z)){
+                if (isSupported(world, x, y, z, Side.WEST)){
                     rotation = ROTATION_EAST;
                 }
                 break;
@@ -125,33 +133,33 @@ public class BlockLogicLever extends BlockLogic
         int rotation = -1;
         switch (side.getOpposite()){
             case BOTTOM:
-                if (world.canPlaceOnSurfaceOfBlock(x, y + 1, z)){
+                if (isSupported(world, x, y, z, Side.TOP)){
                     rotation = ROTATION_BOTTOM_NS;
                 }
                 break;
             case TOP:
-                if (world.canPlaceOnSurfaceOfBlock(x, y - 1, z))
+                if (isSupported(world, x, y, z, Side.BOTTOM))
                 {
                     rotation = ROTATION_TOP_NS;
                 }
                 break;
             case NORTH:
-                if (world.isBlockNormalCube(x, y, z + 1)){
+                if (isSupported(world, x, y, z, Side.SOUTH)){
                     rotation = ROTATION_NORTH;
                 }
                 break;
             case SOUTH:
-                if (world.isBlockNormalCube(x, y, z - 1)){
+                if (isSupported(world, x, y, z, Side.NORTH)){
                     rotation = ROTATION_SOUTH;
                 }
                 break;
             case WEST:
-                if (world.isBlockNormalCube(x + 1, y, z)){
+                if (isSupported(world, x, y, z, Side.EAST)){
                     rotation = ROTATION_WEST;
                 }
                 break;
             case EAST:
-                if (world.isBlockNormalCube(x - 1, y, z)){
+                if (isSupported(world, x, y, z, Side.WEST)){
                     rotation = ROTATION_EAST;
                 }
                 break;
@@ -174,24 +182,24 @@ public class BlockLogicLever extends BlockLogic
             boolean shouldBreak;
             switch (rotation){
                 case ROTATION_EAST:
-                    shouldBreak = !world.isBlockNormalCube(x - 1, y, z);
+                    shouldBreak = !isSupported(world, x, y, z, Side.WEST);
                     break;
                 case ROTATION_WEST:
-                    shouldBreak = !world.isBlockNormalCube(x + 1, y, z);
+                    shouldBreak = !isSupported(world, x, y, z, Side.EAST);
                     break;
                 case ROTATION_SOUTH:
-                    shouldBreak = !world.isBlockNormalCube(x, y, z - 1);
+                    shouldBreak = !isSupported(world, x, y, z, Side.NORTH);
                     break;
                 case ROTATION_NORTH:
-                    shouldBreak = !world.isBlockNormalCube(x, y, z + 1);
+                    shouldBreak = !isSupported(world, x, y, z, Side.SOUTH);
                     break;
                 case ROTATION_TOP_NS:
                 case ROTATION_TOP_WE:
-                    shouldBreak = !world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+                    shouldBreak = !isSupported(world, x, y, z, Side.BOTTOM);
                     break;
                 case ROTATION_BOTTOM_NS:
                 case ROTATION_BOTTOM_WE:
-                    shouldBreak = !world.canPlaceOnSurfaceOfBlock(x, y + 1, z);
+                    shouldBreak = !isSupported(world, x, y, z, Side.TOP);
                     break;
                 default:
                     shouldBreak = false;
@@ -359,4 +367,9 @@ public class BlockLogicLever extends BlockLogic
     {
         return true;
     }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE.center();
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
index 4ecea2b67..000b76589 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMatcher.java
@@ -7,7 +7,6 @@ import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.PlacementMode;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Axis;
-import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
@@ -28,7 +27,7 @@ public class BlockLogicMatcher extends BlockLogicAxisAligned {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         updateState(world, x, y, z);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
index f85515d06..6f793173f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMoss.java
@@ -8,7 +8,6 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
-import net.minecraft.core.world.generate.feature.WorldFeatureOre;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -26,7 +25,7 @@ public class BlockLogicMoss extends BlockLogic implements IBonemealable {
 	}
 
 	@Override
-	public void updateTick(World world, int x, int y, int z, Random rand) {
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
 		if (world.isClientSide) {
 			return;
 		}
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
index ac2356d97..8043cad7e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMud.java
@@ -149,7 +149,7 @@ public class BlockLogicMud extends BlockLogic {
 
 
     @Override
-    public void updateTick(final World world, final int x, final int y, final int z, final Random rand)
+    public void updateTick(final World world, final int x, final int y, final int z, final Random rand, boolean isRandomTick)
     {
         // hydrate mud
         if(isHardened) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMushroom.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMushroom.java
index c6832f164..1f3fe7550 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicMushroom.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicMushroom.java
@@ -1,6 +1,5 @@
 package net.minecraft.core.block;
 
-import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
@@ -21,7 +20,7 @@ public class BlockLogicMushroom extends BlockLogicFlower
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(rand.nextInt(25) == 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
index 1ab71f573..f6f2aca92 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicNetherrackIgneous.java
@@ -59,7 +59,7 @@ public class BlockLogicNetherrackIgneous extends BlockLogic {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         if (canMelt(world, x, y, z)) {
             world.setBlockWithNotify(x, y, z, Blocks.FLUID_LAVA_FLOWING.id());
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java
index bee8f2431..3e73e4728 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOreRedstone.java
@@ -12,7 +12,6 @@ import net.minecraft.core.util.helper.Direction;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 import net.minecraft.core.block.material.Material;
-import net.minecraft.core.world.generate.feature.WorldFeatureOre;
 import net.minecraft.core.world.WorldSource;
 
 import java.util.Random;
@@ -77,7 +76,7 @@ public class BlockLogicOreRedstone extends BlockLogic
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(illuminated)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java
index 4ecb2bf6d..9b835e7a3 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicOverlayPebbles.java
@@ -2,12 +2,17 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class BlockLogicOverlayPebbles extends BlockLogic
 {
@@ -17,6 +22,17 @@ public class BlockLogicOverlayPebbles extends BlockLogic
         setBlockBounds(0, 0, 0, 1, 0.0625F, 1);
     }
 
+    public static boolean canSpawnOn(final @Nullable Block<?> block) {
+        return
+            block == Blocks.GRASS ||
+                block == Blocks.SAND ||
+                block == Blocks.DIRT ||
+                block == Blocks.SANDSTONE ||
+                block == Blocks.DIRT_SCORCHED ||
+                block == Blocks.DIRT_SCORCHED_RICH ||
+                block == Blocks.GRASS_SCORCHED;
+    }
+
     @Override
     public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
@@ -58,6 +74,11 @@ public class BlockLogicOverlayPebbles extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int meta, TileEntity tileEntity)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
index 6de96e93e..eb73cc6e7 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPortal.java
@@ -2,6 +2,8 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.enums.EnumDropCause;
@@ -9,10 +11,12 @@ import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.DyeColor;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.Dimension;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -74,6 +78,11 @@ public class BlockLogicPortal extends BlockLogicTransparent implements IPainted
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     public int[] getPortalDims(World world, int x, int y, int z, boolean expectMiddle)
     {
     	return getPortalDims(world, x, y, z, false, expectMiddle);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
index a16cb0c84..536352f35 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicPressurePlate.java
@@ -1,13 +1,15 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.DyeColor;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.sound.SoundCategory;
-import net.minecraft.core.util.helper.DyeColor;
-import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
@@ -16,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
 import java.util.List;
 import java.util.Random;
 
-public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implements IPaintable
+public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implements IPaintable, ISupportable
 {
     public static final int MASK_POWERED = 0b0000_0001;
     public static final int MASK_SIDE = 0b0000_1110;
@@ -56,29 +58,40 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
     }
 
     @Override
-	public boolean canPlaceBlockAt(World world, int x, int y, int z)
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
+    @Override
+    public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z) ||
-            world.isBlockNormalCube(x, y + 1, z) ||
-            world.isBlockNormalCube(x + 1, y, z) ||
-            world.isBlockNormalCube(x - 1, y, z) ||
-            world.isBlockNormalCube(x, y, z + 1) ||
-            world.isBlockNormalCube(x, y, z - 1);
+        return isSupported(world, x, y, z, Side.BOTTOM)
+            || isSupported(world, x, y, z, Side.TOP)
+            || isSupported(world, x, y, z, Side.NORTH)
+            || isSupported(world, x, y, z, Side.SOUTH)
+            || isSupported(world, x, y, z, Side.WEST)
+            || isSupported(world, x, y, z, Side.EAST);
     }
 
     @Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
     {
-        boolean flag = !canPlaceBlockAt(world, x, y, z);
-        if(flag)
-        {
+        if(!isSupported(world, x, y, z, sideFromMeta(world.getBlockMetadata(x, y, z)))) {
             dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), null, null);
             world.setBlockWithNotify(x, y, z, 0);
         }
     }
 
+    private Side getDefaultSide(World world, int x, int y, int z) {
+        for (int i = 0; i < Side.sides.length; i++) {
+            Side side = Side.sides[i];
+            if (isSupported(world, x, y, z, side)) return side;
+        }
+        return Side.NONE;
+    }
+
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
@@ -119,13 +132,10 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
             default: list = world.getEntitiesWithinAABB(triggerMobClass, AABB.fromPool(1 - (isPressed ? pixel/2f : pixel), pixel, pixel, 1, 1 - pixel, 1 - pixel).move(x, y, z)); break;
         }
 
-        if(list != null)
-        {
-            for (int i = 0; i < list.size(); i++) {
-                if (list.get(i).canInteract()) {
-                    isSteppedOn = true;
-                    break;
-                }
+        for (int i = 0; i < list.size(); i++) {
+            if (list.get(i).canInteract()) {
+                isSteppedOn = true;
+                break;
             }
         }
         if(isSteppedOn && !isPressed)
@@ -221,12 +231,18 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
     }
     @Override
     public void onBlockPlacedOnSide(World world, int x, int y, int z, @NotNull Side side, double xPlaced, double yPlaced) {
+        int meta = world.getBlockMetadata(x, y, z);
         side = side.getOpposite();
-        if (world.isBlockNormalCube(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ())) {
-            world.setBlockMetadata(x, y, z, setSide(world.getBlockMetadata(x, y, z), side));
-        } else if (world.canPlaceOnSurfaceOfBlock(x, y - 1, z)) {
-            world.setBlockMetadata(x, y, z, setSide(world.getBlockMetadata(x, y, z), Side.BOTTOM));
+        if (!isSupported(world, x, y, z, side)) {
+            side = getDefaultSide(world, x, y, z);
+        }
+        if (side != Side.NONE) {
+            world.setBlockMetadata(x, y, z, setSide(meta, side));
+        } else {
+            dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, meta, null, null);
+            world.setBlockWithNotify(x, y, z, 0);
         }
+
     }
 
     @Override
@@ -244,4 +260,9 @@ public class BlockLogicPressurePlate<T extends Entity> extends BlockLogic implem
             world.scheduleBlockUpdate(x, y, z, Blocks.PRESSURE_PLATE_PLANKS_OAK_PAINTED.id(), tickDelay());
         }
     }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE.center();
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
index cb611e085..223eabee6 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRail.java
@@ -2,12 +2,16 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.logic.RailDirection;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.Axis;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.chunk.ChunkPosition;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -67,6 +71,11 @@ public class BlockLogicRail extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z) {
         return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
index fa4ede3d8..d025a2480 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRailDetector.java
@@ -40,7 +40,7 @@ public class BlockLogicRailDetector extends BlockLogicRail {
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand) {
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         if(world.isClientSide) {
             return;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
index 3eff1421b..24981746a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRepeater.java
@@ -3,6 +3,8 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
@@ -46,6 +48,11 @@ public class BlockLogicRepeater extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
@@ -77,7 +84,7 @@ public class BlockLogicRepeater extends BlockLogic
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand) {
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         int meta = world.getBlockMetadata(x, y, z);
         boolean flag = isGettingPower(world, x, y, z, meta);
         if(isRepeaterPowered && !flag) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
index ce16bbeec..b81f01b3a 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicRope.java
@@ -2,6 +2,8 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
 import net.minecraft.core.enums.EnumDropCause;
@@ -12,6 +14,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicRope
     extends BlockLogic {
@@ -30,6 +33,11 @@ public class BlockLogicRope
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean isClimbable(World world, int x, int y, int z) {
         return true;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSand.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSand.java
index df35ba8a5..d24012e0b 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSand.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSand.java
@@ -1,13 +1,9 @@
 package net.minecraft.core.block;
 
-import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.EntityFallingBlock;
 import net.minecraft.core.block.material.Material;
-import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.World;
-import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
 
@@ -32,7 +28,7 @@ public class BlockLogicSand extends BlockLogic
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         tryToFall(world, x, y, z);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java
index e90f16de9..ce4299990 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingBase.java
@@ -28,7 +28,7 @@ public abstract class BlockLogicSaplingBase extends BlockLogicFlower implements
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
@@ -41,7 +41,7 @@ public abstract class BlockLogicSaplingBase extends BlockLogicFlower implements
             }	
         }
 
-        super.updateTick(world, x, y, z, rand);
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         int growthRate = 30;
         if(world.getSeasonManager().getCurrentSeason() != null){
             growthRate = MathHelper.floor_float(growthRate / world.getSeasonManager().getCurrentSeason().cropGrowthFactor);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingPine.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingPine.java
index 0ec3595da..944aa8e74 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingPine.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSaplingPine.java
@@ -16,13 +16,13 @@ public class BlockLogicSaplingPine extends BlockLogicSaplingBase
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand)
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isClientSide)
         {
             return;
         }
-        super.updateTick(world, x, y, z, rand);
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         int growthRate = 30;
         if(world.getBlockLightValue(x, y + 1, z) >= 9 && rand.nextInt(growthRate) == 0)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
index b971b8d49..9cea92379 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSeat.java
@@ -3,12 +3,15 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntitySeat;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Items;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicSeat extends BlockLogic
 {
@@ -54,6 +57,11 @@ public class BlockLogicSeat extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int meta, TileEntity tileEntity) {
         if (dropCause != EnumDropCause.IMPROPER_TOOL)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
index 00009d94f..aa9431773 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSign.java
@@ -4,6 +4,8 @@ import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntitySign;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
@@ -13,6 +15,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicSign extends BlockLogic implements IPaintable
 {
@@ -75,6 +78,11 @@ public class BlockLogicSign extends BlockLogic implements IPaintable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
 	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
index 6cc101808..2efdb8f6e 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSlab.java
@@ -3,6 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.MaterialColor;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
@@ -25,6 +28,11 @@ public class BlockLogicSlab extends BlockLogic
     public Block<?> modelBlock;
     public int modelBlockMetadata;
 
+    public static final int MASK_STATE = 0b11;
+    public static final int STATE_LOWER = 0;
+    public static final int STATE_DOUBLE = 1;
+    public static final int STATE_UPPER = 2;
+
     public BlockLogicSlab(Block<?> block, Block<?> modelBlock)
     {
         this(block, modelBlock, 0);
@@ -54,13 +62,13 @@ public class BlockLogicSlab extends BlockLogic
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z)
     {
-        int l = world.getBlockMetadata(x, y, z) & 0x3;
+        int l = world.getBlockMetadata(x, y, z) & MASK_STATE;
         switch (l) {
-            case 0:
+            case STATE_LOWER:
                 return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
-            case 1:
+            case STATE_DOUBLE:
                 return AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
-            case 2:
+            case STATE_UPPER:
             default:
                 return AABB.fromPool(0.0F, 0.5F, 0.0F, 1.0F, 1.0F, 1.0F);
         }
@@ -77,14 +85,31 @@ public class BlockLogicSlab extends BlockLogic
     public boolean renderAsNormalBlockOnCondition(WorldSource world, int x, int y, int z)
     {
         int meta = world.getBlockMetadata(x, y, z);
-        return (meta & 0x3) == 1;
+        return (meta & MASK_STATE) == STATE_DOUBLE;
     }
 
     @Override
     public boolean canPlaceOnSurfaceOnCondition(World world, int x, int y, int z)
     {
         int meta = world.getBlockMetadata(x, y, z);
-        return (meta & 0x3) != 0;
+        return (meta & MASK_STATE) != STATE_LOWER;
+    }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int state = world.getBlockMetadata(x, y, z) & MASK_STATE;
+        switch (side) {
+            case TOP: return state == STATE_UPPER || state == STATE_DOUBLE ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            case BOTTOM: return state == STATE_LOWER || state == STATE_DOUBLE ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            default:
+                switch (state) {
+                    case STATE_LOWER: return PartialSupport.INSTANCE.down();
+                    case STATE_UPPER: return PartialSupport.INSTANCE.up();
+                    case STATE_DOUBLE:
+                    default:
+                        return FullSupport.INSTANCE;
+                }
+        }
     }
 
     @Override
@@ -98,7 +123,7 @@ public class BlockLogicSlab extends BlockLogic
             {
                 stack.setMetadata(meta & 0xF0);
                 stack.itemID = this.id();
-                if ((meta & 0b11) == 1 && dropCause != EnumDropCause.PICK_BLOCK) stack.stackSize = 2;
+                if ((meta & MASK_STATE) == STATE_DOUBLE && dropCause != EnumDropCause.PICK_BLOCK) stack.stackSize = 2;
                 else stack.stackSize = 1;
             }
         }
@@ -142,9 +167,9 @@ public class BlockLogicSlab extends BlockLogic
         modelBlock.onEntityWalking(world, x, y, z, entity);
     }
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
-        modelBlock.updateTick(world, x, y, z, rand);
+        modelBlock.updateTick(world, x, y, z, rand, false);
     }
     @Override
     public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSnow.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSnow.java
index 16ec10324..ec56a7e0f 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSnow.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSnow.java
@@ -20,7 +20,7 @@ public class BlockLogicSnow extends BlockLogic
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.getSavedLightValue(LightLayer.Block, x, y, z) > 11)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
index 1c815a00b..bac712460 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSpikes.java
@@ -1,6 +1,9 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.Mob;
@@ -117,4 +120,9 @@ public class BlockLogicSpikes extends BlockLogic
     public boolean isCubeShaped() {
         return false;
     }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side == Side.BOTTOM ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+    }
 }
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
index 76b42e69b..83d9ab602 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStairs.java
@@ -6,6 +6,9 @@ import java.util.Random;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.material.MaterialColor;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.util.phys.Vec3;
@@ -82,6 +85,89 @@ public class BlockLogicStairs extends BlockLogic
 //        vol.bake();
 //        selectionVolumes.put(0b1011, vol);
 //    }
+    public static final int MASK_ROTATION_HORIZONTAL = 0b0000_0011;
+    public static final int MASK_ROTATION_VERTICAL = 0b0000_1000;
+
+    public static final int H_ROTATION_WEST = 0;
+    public static final int H_ROTATION_EAST = 1;
+    public static final int H_ROTATION_NORTH = 2;
+    public static final int H_ROTATION_SOUTH = 3;
+
+    public static final ISupport[] lowerStairsSupportMapping = {
+        // Side Bottom
+        FullSupport.INSTANCE,       // West
+        FullSupport.INSTANCE,       // East
+        FullSupport.INSTANCE,       // North
+        FullSupport.INSTANCE,       // South
+
+        // Side Top
+        PartialSupport.INSTANCE.right(),    // West
+        PartialSupport.INSTANCE.left(),    // East
+        PartialSupport.INSTANCE.down(),    // North
+        PartialSupport.INSTANCE.up(),    // South
+
+        // Side North
+        PartialSupport.INSTANCE.down().right(),    // West
+        PartialSupport.INSTANCE.down().left(),    // East
+        PartialSupport.INSTANCE.down(),    // North
+        FullSupport.INSTANCE,       // South
+
+        // Side South
+        PartialSupport.INSTANCE.down().right(),    // West
+        PartialSupport.INSTANCE.down().left(),    // East
+        FullSupport.INSTANCE,       // North
+        PartialSupport.INSTANCE.down(),    // South
+
+        // Side West
+        PartialSupport.INSTANCE.down(),    // West
+        FullSupport.INSTANCE,       // East
+        PartialSupport.INSTANCE.down().left(),    // North
+        PartialSupport.INSTANCE.down().right(),    // South
+
+        // Side East
+        FullSupport.INSTANCE,       // West
+        PartialSupport.INSTANCE.down(),    // East
+        PartialSupport.INSTANCE.down().left(),    // North
+        PartialSupport.INSTANCE.down().right(),    // South
+    };
+
+    public static final ISupport[] upperStairsSupportMapping = {
+        // Side Bottom
+        PartialSupport.INSTANCE.right(),    // West
+        PartialSupport.INSTANCE.left(),    // East
+        PartialSupport.INSTANCE.down(),    // North
+        PartialSupport.INSTANCE.up(),    // South
+
+        // Side Top
+        FullSupport.INSTANCE,       // West
+        FullSupport.INSTANCE,       // East
+        FullSupport.INSTANCE,       // North
+        FullSupport.INSTANCE,       // South
+
+        // Side North
+        PartialSupport.INSTANCE.up().right(),    // West
+        PartialSupport.INSTANCE.up().left(),    // East
+        PartialSupport.INSTANCE.up(),    // North
+        FullSupport.INSTANCE,       // South
+
+        // Side South
+        PartialSupport.INSTANCE.up().right(),    // West
+        PartialSupport.INSTANCE.up().left(),    // East
+        FullSupport.INSTANCE,       // North
+        PartialSupport.INSTANCE.up(),    // South
+
+        // Side West
+        PartialSupport.INSTANCE.up(),    // West
+        FullSupport.INSTANCE,       // East
+        PartialSupport.INSTANCE.up().left(),    // North
+        PartialSupport.INSTANCE.up().right(),    // South
+
+        // Side East
+        FullSupport.INSTANCE,       // West
+        PartialSupport.INSTANCE.up(),    // East
+        PartialSupport.INSTANCE.up().left(),    // North
+        PartialSupport.INSTANCE.up().right(),    // South
+    };
 
     public Block<?> modelBlock;
 
@@ -117,31 +203,43 @@ public class BlockLogicStairs extends BlockLogic
 
     @Override
     public boolean canPlaceOnSurfaceOnCondition(World world, int x, int y, int z) {
-    	return (world.getBlockMetadata(x, y, z) & 8) > 0;
+    	return (world.getBlockMetadata(x, y, z) & MASK_ROTATION_VERTICAL) != 0;
+    }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int meta = world.getBlockMetadata(x, y, z);
+        int hRot = meta & MASK_ROTATION_HORIZONTAL;
+        if ((meta & MASK_ROTATION_VERTICAL) != 0) {
+            return upperStairsSupportMapping[side.getId() * 4 + hRot];
+        } else {
+            return lowerStairsSupportMapping[side.getId() * 4 + hRot];
+        }
     }
 
     @Override
     public void getCollidingBoundingBoxes(World world, int x, int y, int z, AABB aabb, ArrayList<AABB> aabbList)
     {
         int meta = world.getBlockMetadata(x, y, z);
-        int hRotation = meta & 0b0011;
-        int vRotation = meta & 0b1000;
+        int hRotation = meta & MASK_ROTATION_HORIZONTAL;
+        int vRotation = meta & MASK_ROTATION_VERTICAL;
 
-        float stepYOffset = vRotation > 0 ? 0.5f : 0.0f;
+        float stepYOffset = vRotation != 0 ? 0.5f : 0.0f;
 
         switch (hRotation) {
-            case 0:
+            case H_ROTATION_WEST:
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.0F, 0.5F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
                 break;
-            case 1:
+            case H_ROTATION_EAST:
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F).move(x, y, z), aabbList);
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.5F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
                 break;
-            case 2:
+            case H_ROTATION_NORTH:
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.0F, 1.0F, 0.5F + stepYOffset, 0.5F).move(x, y, z), aabbList);
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F).move(x, y, z), aabbList);
                 break;
+            case H_ROTATION_SOUTH:
             default:
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F).move(x, y, z), aabbList);
                 addIntersectingBoundingBox(aabb, AABB.fromPool(0.0F, 0.0F + stepYOffset, 0.5F, 1.0F, 0.5F + stepYOffset, 1.0F).move(x, y, z), aabbList);
@@ -242,9 +340,9 @@ public class BlockLogicStairs extends BlockLogic
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
-        modelBlock.updateTick(world, x, y, z, rand);
+        modelBlock.updateTick(world, x, y, z, rand, false);
     }
 
     @Override
@@ -266,14 +364,14 @@ public class BlockLogicStairs extends BlockLogic
         int meta = world.getBlockMetadata(x, y, z) & 0xF0;
 
         Direction hRotation = mob.getHorizontalPlacementDirection(side).getOpposite();
-        if(hRotation == Direction.NORTH) meta |= 0b0010;
-        if(hRotation == Direction.EAST) meta |= 0b0001;
-        if(hRotation == Direction.SOUTH) meta |= 0b0011;
-        if(hRotation == Direction.WEST) meta |= 0b0000;
+        if(hRotation == Direction.NORTH) meta |= H_ROTATION_NORTH;
+        if(hRotation == Direction.EAST) meta |= H_ROTATION_EAST;
+        if(hRotation == Direction.SOUTH) meta |= H_ROTATION_SOUTH;
+        if(hRotation == Direction.WEST) meta |= H_ROTATION_WEST;
 
         Direction vRotation = mob.getVerticalPlacementDirection(side, yPlaced);
-        if (vRotation == Direction.DOWN) meta |= 0b0000;
-        if (vRotation == Direction.UP) meta |= 0b1000;
+//        if (vRotation == Direction.DOWN) meta |= 0b0000;
+        if (vRotation == Direction.UP) meta |= MASK_ROTATION_VERTICAL;
 
         world.setBlockMetadataWithNotify(x, y, z, meta);
     }
@@ -285,15 +383,15 @@ public class BlockLogicStairs extends BlockLogic
         side = side.getOpposite();
         Side hSide = !side.isHorizontal() ? Side.NORTH : side;
         Direction hRotation = hSide.getOpposite().getDirection();
-        if(hRotation == Direction.NORTH) meta |= 0b0010;
-        if(hRotation == Direction.EAST) meta |= 0b0001;
-        if(hRotation == Direction.SOUTH) meta |= 0b0011;
-        if(hRotation == Direction.WEST) meta |= 0b0000;
+        if(hRotation == Direction.NORTH) meta |= H_ROTATION_NORTH;
+        if(hRotation == Direction.EAST) meta |= H_ROTATION_EAST;
+        if(hRotation == Direction.SOUTH) meta |= H_ROTATION_SOUTH;
+        if(hRotation == Direction.WEST) meta |= H_ROTATION_WEST;
 
         Side vSide = !side.isVertical() ? Side.BOTTOM : side;
         Direction vRotation = vSide.getDirection();
-        if (vRotation == Direction.DOWN) meta |= 0b0000;
-        if (vRotation == Direction.UP) meta |= 0b1000;
+//        if (vRotation == Direction.DOWN) meta |= 0b0000;
+        if (vRotation == Direction.UP) meta |= MASK_ROTATION_VERTICAL;
 
         world.setBlockMetadataWithNotify(x, y, z, meta);
     }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStalk.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStalk.java
index 8f369d1be..a669f0831 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStalk.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStalk.java
@@ -1,9 +1,14 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicStalk extends BlockLogic {
     public BlockLogicStalk(Block<?> block) {
@@ -33,6 +38,11 @@ public class BlockLogicStalk extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z) {
         return null;
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
index d5b1c3008..7dd5c0d94 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicStatue.java
@@ -3,6 +3,9 @@ package net.minecraft.core.block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityStatue;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.enums.HumanArmorShape;
@@ -157,6 +160,11 @@ public class BlockLogicStatue extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     public @Nullable TileEntityStatue getTileEntity(final @NotNull World world, final int x, final int y, final int z) {
         final @Nullable Block<?> block = world.getBlock(x, this.isBottom ? y : y - 1, z);
         if (block == null || !(block.getLogic() instanceof BlockLogicStatue)) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java
index c06688617..3c585db62 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicSugarcane.java
@@ -1,6 +1,8 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.IBonemealable;
 import net.minecraft.core.util.helper.Side;
@@ -12,6 +14,7 @@ import net.minecraft.core.block.material.Material;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Random;
@@ -28,7 +31,7 @@ public class BlockLogicSugarcane extends BlockLogic implements IBonemealable
     }
 
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
         if(world.isAirBlock(x, y + 1, z))
         {
@@ -133,6 +136,11 @@ public class BlockLogicSugarcane extends BlockLogic implements IBonemealable
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean onBonemealUsed(ItemStack itemstack, @Nullable Player player, World world, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
         if(!world.isClientSide)
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
index 277320a62..014894a41 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorch.java
@@ -1,6 +1,9 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.Side;
@@ -11,7 +14,7 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
-public class BlockLogicTorch extends BlockLogic
+public class BlockLogicTorch extends BlockLogic implements ISupportable
 {
     public static final int MASK_DIRECTION = 0b0000_0111;
     public static final int SIDE_NONE = 0;
@@ -66,79 +69,20 @@ public class BlockLogicTorch extends BlockLogic
         return false;
     }
 
-    private boolean canPlaceOnTop(World world, int x, int y, int z)
-    {
-        int blockBelow = world.getBlockId(x, y, z);
-        return world.canPlaceOnSurfaceOfBlock(x, y, z)
-            || blockBelow == Blocks.FENCE_PLANKS_OAK.id()
-            || blockBelow == Blocks.FENCE_PLANKS_OAK_PAINTED.id()
-            || blockBelow == Blocks.FENCE_CHAINLINK.id()
-            || blockBelow == Blocks.FENCE_PAPER_WALL.id()
-            || blockBelow == Blocks.FENCE_STEEL.id();
-    }
-
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            return true;
-        }
-        if(world.isBlockNormalCube(x, y, z + 1))
-        {
-            return true;
-        }
-        return canPlaceOnTop(world, x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM)
+            || isSupported(world, x, y, z, Side.NORTH)
+            || isSupported(world, x, y, z, Side.SOUTH)
+            || isSupported(world, x, y, z, Side.WEST)
+            || isSupported(world, x, y, z, Side.EAST);
     }
 
     @Override
     public void onBlockPlacedByMob(World world, int x, int y, int z, @NotNull Side side, Mob mob, double xPlaced, double yPlaced) {
-        int orientation = SIDE_NONE;
-        switch (side) {
-            case TOP:
-                if(canPlaceOnTop(world, x, y - 1, z))
-                {
-                    orientation = SIDE_BOTTOM;
-                }
-                break;
-            case NORTH:
-                if(world.isBlockNormalCube(x, y, z + 1))
-                {
-                    orientation = SIDE_SOUTH;
-                }
-                break;
-            case SOUTH:
-                if(world.isBlockNormalCube(x, y, z - 1))
-                {
-                    orientation = SIDE_NORTH;
-                }
-                break;
-            case WEST:
-                if(world.isBlockNormalCube(x + 1, y, z))
-                {
-                    orientation = SIDE_EAST;
-                }
-                break;
-            case EAST:
-                if(world.isBlockNormalCube(x - 1, y, z))
-                {
-                    orientation = SIDE_WEST;
-                }
-                break;
-        }
-        if (orientation == SIDE_NONE) {
-            orientation = getDefaultOrientation(world, x, y, z);
-        }
-        world.setBlockMetadataWithNotify(x, y, z, orientation);
-        dropTorchIfCantStay(world, x, y, z);
+        if (side.isHorizontal()) side = side.getOpposite();
+        onBlockPlacedOnSide(world, x, y, z, side, xPlaced, yPlaced);
     }
 
     @Override
@@ -147,32 +91,27 @@ public class BlockLogicTorch extends BlockLogic
         if (side.isHorizontal()) side = side.getOpposite();
         switch (side) {
             case TOP:
-                if(canPlaceOnTop(world, x, y - 1, z))
-                {
+                if(isSupported(world, x, y, z, Side.BOTTOM)) {
                     orientation = SIDE_BOTTOM;
                 }
                 break;
             case NORTH:
-                if(world.isBlockNormalCube(x, y, z + 1))
-                {
+                if(isSupported(world, x, y, z, Side.SOUTH)) {
                     orientation = SIDE_SOUTH;
                 }
                 break;
             case SOUTH:
-                if(world.isBlockNormalCube(x, y, z - 1))
-                {
+                if(isSupported(world, x, y, z, Side.NORTH)) {
                     orientation = SIDE_NORTH;
                 }
                 break;
             case WEST:
-                if(world.isBlockNormalCube(x + 1, y, z))
-                {
+                if(isSupported(world, x, y, z, Side.EAST)) {
                     orientation = SIDE_EAST;
                 }
                 break;
             case EAST:
-                if(world.isBlockNormalCube(x - 1, y, z))
-                {
+                if(isSupported(world, x, y, z, Side.WEST)) {
                     orientation = SIDE_WEST;
                 }
                 break;
@@ -185,32 +124,24 @@ public class BlockLogicTorch extends BlockLogic
     }
 
     public int getDefaultOrientation(World world, int x, int y, int z) {
-        if (canPlaceOnTop(world, x, y - 1, z)) {
+        if(isSupported(world, x, y, z, Side.BOTTOM)) {
             return SIDE_BOTTOM;
-        }
-        if(world.isBlockNormalCube(x, y, z + 1))
-        {
-            return SIDE_SOUTH;
-        }
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            return SIDE_NORTH;
-        }
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            return SIDE_EAST;
-        }
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
+        } else if(isSupported(world, x, y, z, Side.WEST)) {
             return SIDE_WEST;
+        } else if(isSupported(world, x, y, z, Side.EAST)) {
+            return SIDE_EAST;
+        } else if(isSupported(world, x, y, z, Side.NORTH)) {
+            return SIDE_NORTH;
+        } else if(isSupported(world, x, y, z, Side.SOUTH)) {
+            return SIDE_SOUTH;
         }
         return SIDE_NONE;
     }
     
     @Override
-	public void updateTick(World world, int x, int y, int z, Random rand)
+	public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick)
     {
-        super.updateTick(world, x, y, z, rand);
+        super.updateTick(world, x, y, z, rand, isRandomTick);
         if(world.getBlockMetadata(x, y, z) == SIDE_NONE)
         {
             onBlockPlacedByWorld(world, x, y, z);
@@ -220,25 +151,9 @@ public class BlockLogicTorch extends BlockLogic
     @Override
 	public void onBlockPlacedByWorld(World world, int x, int y, int z)
     {
-        if(world.isBlockNormalCube(x - 1, y, z))
-        {
-            world.setBlockMetadataWithNotify(x, y, z, SIDE_WEST);
-        } else
-        if(world.isBlockNormalCube(x + 1, y, z))
-        {
-            world.setBlockMetadataWithNotify(x, y, z, SIDE_EAST);
-        } else
-        if(world.isBlockNormalCube(x, y, z - 1))
-        {
-            world.setBlockMetadataWithNotify(x, y, z, SIDE_NORTH);
-        } else
-        if(world.isBlockNormalCube(x, y, z + 1))
-        {
-            world.setBlockMetadataWithNotify(x, y, z, SIDE_SOUTH);
-        } else
-        if(canPlaceOnTop(world, x, y - 1, z))
-        {
-            world.setBlockMetadataWithNotify(x, y, z, SIDE_BOTTOM);
+        int orientation = getDefaultOrientation(world, x, y, z);
+        if (orientation != SIDE_NONE) {
+            world.setBlockMetadataWithNotify(x, y, z, orientation);
         }
         dropTorchIfCantStay(world, x, y, z);
     }
@@ -250,25 +165,19 @@ public class BlockLogicTorch extends BlockLogic
         int side = world.getBlockMetadata(x, y, z) & MASK_DIRECTION;
         switch (side) {
             case SIDE_WEST:
-                invalid = !world.isBlockNormalCube(x - 1, y, z);
+                invalid = !isSupported(world, x, y, z, Side.WEST);
                 break;
             case SIDE_EAST:
-                invalid = !world.isBlockNormalCube(x + 1, y, z);
+                invalid = !isSupported(world, x, y, z, Side.EAST);
                 break;
             case SIDE_NORTH:
-                invalid = !world.isBlockNormalCube(x, y, z - 1);
+                invalid = !isSupported(world, x, y, z, Side.NORTH);
                 break;
             case SIDE_SOUTH:
-                invalid = !world.isBlockNormalCube(x, y, z + 1);
+                invalid = !isSupported(world, x, y, z, Side.SOUTH);
                 break;
             case SIDE_BOTTOM:
-                int blockBelow = world.getBlockId(x, y - 1, z);
-                invalid = !(world.canPlaceOnSurfaceOfBlock(x, y - 1, z)
-                    || blockBelow == Blocks.FENCE_PLANKS_OAK.id()
-                    || blockBelow == Blocks.FENCE_PLANKS_OAK_PAINTED.id()
-                    || blockBelow == Blocks.FENCE_CHAINLINK.id()
-                    || blockBelow == Blocks.FENCE_PAPER_WALL.id()
-                    || blockBelow == Blocks.FENCE_STEEL.id());
+                invalid = !isSupported(world, x, y, z, Side.BOTTOM);
                 break;
             default:
                 invalid = true;
@@ -280,16 +189,11 @@ public class BlockLogicTorch extends BlockLogic
         }
     }
 
-    private boolean dropTorchIfCantStay(World world, int x, int y, int z)
+    private void dropTorchIfCantStay(World world, int x, int y, int z)
     {
-        if(!canPlaceBlockAt(world, x, y, z))
-        {
+        if(!canPlaceBlockAt(world, x, y, z)) {
             dropBlockWithCause(world, EnumDropCause.WORLD, x, y, z, world.getBlockMetadata(x, y, z), null, null);
             world.setBlockWithNotify(x, y, z, 0);
-            return false;
-        } else
-        {
-            return true;
         }
     }
 
@@ -330,4 +234,22 @@ public class BlockLogicTorch extends BlockLogic
     public int getLightmapCoord(WorldSource blockAccess, int x, int y, int z) {
 		return blockAccess.getLightmapCoord(x, y, z, block.emission > 0 ? 15 : 0);
     }
+
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        switch (side) {
+            case NORTH:
+            case SOUTH:
+            case WEST:
+            case EAST:
+            case BOTTOM:
+                return PartialSupport.INSTANCE.center();
+        }
+        return PartialSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
index 19e7dd9b4..008e95d36 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTorchRedstone.java
@@ -90,7 +90,7 @@ public class BlockLogicTorchRedstone extends BlockLogicTorch {
     }
 
     @Override
-    public void updateTick(World world, int x, int y, int z, Random rand) {
+    public void updateTick(World world, int x, int y, int z, Random rand, boolean isRandomTick) {
         boolean isPowered = hasNeighborSignal(world, x, y, z);
         if (torchActive) {
             if (isPowered) {
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
index 834428ec4..f5900962c 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicTrapDoor.java
@@ -2,6 +2,9 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntityActivator;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.PlacementMode;
 import net.minecraft.core.item.Item;
@@ -55,6 +58,31 @@ public class BlockLogicTrapDoor extends BlockLogic implements IPaintable {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int meta = world.getBlockMetadata(x, y, z);
+
+        if (isTrapdoorOpen(meta)) {
+            switch (meta & MASK_DIRECTION) {
+                case DIRECTION_SOUTH:  // South
+                    return side == Side.SOUTH ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+                case DIRECTION_NORTH:  // North
+                    return side == Side.NORTH ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+                case DIRECTION_EAST:  // East
+                    return side == Side.EAST ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+                case DIRECTION_WEST:  // West
+                default:
+                    return side == Side.WEST ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            }
+        } else {
+            if (isUpperHalf(meta)) {
+                return side == Side.TOP ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            } else {
+                return side == Side.BOTTOM ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+            }
+        }
+    }
+
     @Override
     public AABB getBlockBoundsFromState(WorldSource world, int x, int y, int z) {
         int meta = world.getBlockMetadata(x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java
index a88ced793..841e1d3fb 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicWireRedstone.java
@@ -2,6 +2,9 @@ package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.current.util.BlockPos;
 import net.minecraft.core.current.util.BlockState;
 import net.minecraft.core.enums.EnumDropCause;
@@ -13,13 +16,14 @@ import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.chunk.ChunkPosition;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Random;
 import java.util.Set;
 
-public class BlockLogicWireRedstone extends BlockLogic {
+public class BlockLogicWireRedstone extends BlockLogic implements ISupportable {
     public static final int SIGNAL_MIN = 0;
     public static final int SIGNAL_MAX = 15;
     public static final int SIGNAL_STEP = 1;
@@ -49,9 +53,14 @@ public class BlockLogicWireRedstone extends BlockLogic {
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return PartialSupport.INSTANCE;
+    }
+
     @Override
     public boolean canPlaceBlockAt(World world, int x, int y, int z) {
-        return world.canPlaceOnSurfaceOfBlock(x, y - 1, z);
+        return isSupported(world, x, y, z, Side.BOTTOM);
     }
 
     private void updatePowerStrength(World world, int x, int y, int z) {
@@ -402,4 +411,9 @@ public class BlockLogicWireRedstone extends BlockLogic {
         int blockId = worldSource.getBlockId(x, y, z);
         return blockId == Blocks.WIRE_REDSTONE.id();
     }
+
+    @Override
+    public @NotNull ISupport getSupportConstraint(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        return side == Side.BOTTOM ? PartialSupport.INSTANCE.center() : PartialSupport.INSTANCE;
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/Blocks.java b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
index 09d260d1b..42dea22a9 100644
--- a/game/core/src/main/java/net/minecraft/core/block/Blocks.java
+++ b/game/core/src/main/java/net/minecraft/core/block/Blocks.java
@@ -9,6 +9,7 @@ import net.minecraft.core.block.piston.BlockLogicPistonHead;
 import net.minecraft.core.block.piston.BlockLogicPistonMoving;
 import net.minecraft.core.block.piston.BlockLogicPistonBaseSteel;
 import net.minecraft.core.block.piston.BlockLogicPistonBaseSticky;
+import net.minecraft.core.block.support.ISupportable;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.data.tag.Tag;
 import net.minecraft.core.entity.Entity;
@@ -726,7 +727,7 @@ public final class Blocks {
         .withSound(BlockSounds.STONE).withHardness(3F).withBlastResistance(10F).withOverrideColor(MaterialColor.coal)
         .withTags(BlockTags.MINEABLE_BY_PICKAXE);
 
-    public static final Block<?> WIRE_REDSTONE = register("wire.redstone", "minecraft:block/wire_redstone", 450, BlockLogicWireRedstone::new)
+    public static final Block<BlockLogicWireRedstone> WIRE_REDSTONE = register("wire.redstone", "minecraft:block/wire_redstone", 450, BlockLogicWireRedstone::new)
         .withSound(BlockSounds.STONE).withHardness(0.0F).withDisabledNeighborNotifyOnMetadataChange().withOverrideColor(MaterialColor.redstone).setStatParent(() -> Items.DUST_REDSTONE)
         .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS);
 
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
index d1230c773..3be3df204 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonBase.java
@@ -5,6 +5,9 @@ import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.Mob;
 import net.minecraft.core.entity.player.Player;
@@ -28,6 +31,51 @@ public class BlockLogicPistonBase extends BlockLogic
     public static final int EVENT_EXTEND = 0;
     public static final int EVENT_RETRACT = 1;
 
+    public static final ISupport[] pistonSupportLookupTable = {
+        // Bottom
+        PartialSupport.INSTANCE,
+        FullSupport.INSTANCE,
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().down(),
+        PartialSupport.INSTANCE.center().right(),
+        PartialSupport.INSTANCE.center().left(),
+        // Top
+        FullSupport.INSTANCE,
+        PartialSupport.INSTANCE,
+        PartialSupport.INSTANCE.center().down(),
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().right(),
+        PartialSupport.INSTANCE.center().left(),
+        // North
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().down(),
+        PartialSupport.INSTANCE,
+        FullSupport.INSTANCE,
+        PartialSupport.INSTANCE.center().right(),
+        PartialSupport.INSTANCE.center().left(),
+        // South
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().down(),
+        FullSupport.INSTANCE,
+        PartialSupport.INSTANCE,
+        PartialSupport.INSTANCE.center().right(),
+        PartialSupport.INSTANCE.center().left(),
+        // West
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().down(),
+        PartialSupport.INSTANCE.center().left(),
+        PartialSupport.INSTANCE.center().right(),
+        PartialSupport.INSTANCE,
+        FullSupport.INSTANCE,
+        // East
+        PartialSupport.INSTANCE.center().up(),
+        PartialSupport.INSTANCE.center().down(),
+        PartialSupport.INSTANCE.center().left(),
+        PartialSupport.INSTANCE.center().right(),
+        FullSupport.INSTANCE,
+        PartialSupport.INSTANCE,
+    };
+
     private final int maxPushedBlocks;
 
     public BlockLogicPistonBase(Block<?> block, int maxPushedBlocks)
@@ -214,6 +262,14 @@ public class BlockLogicPistonBase extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int meta = world.getBlockMetadata(x, y, z);
+        if ((meta & MASK_POWERED) == 0) return FullSupport.INSTANCE;
+        Direction dir = getDirection(meta);
+        return pistonSupportLookupTable[side.getId() * 6 + dir.getId()];
+    }
+
     public static Direction getDirection(int data)
     {
         return Direction.getDirectionById(data & MASK_DIRECTION);
diff --git a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
index 243c3c75d..af08e52fc 100644
--- a/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
+++ b/game/core/src/main/java/net/minecraft/core/block/piston/BlockLogicPistonHead.java
@@ -7,6 +7,9 @@ import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Direction;
@@ -14,6 +17,7 @@ import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
+import org.jetbrains.annotations.NotNull;
 
 public class BlockLogicPistonHead extends BlockLogic
 {
@@ -69,6 +73,12 @@ public class BlockLogicPistonHead extends BlockLogic
         return false;
     }
 
+    @Override
+    public @NotNull ISupport getSupport(@NotNull World world, int x, int y, int z, @NotNull Side side) {
+        int meta = world.getBlockMetadata(x, y, z);
+        return getDirectionFromMeta(meta).getSide() == side ? FullSupport.INSTANCE : PartialSupport.INSTANCE;
+    }
+
     @Override
 	public boolean canPlaceBlockAt(World world, int x, int y, int z)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/block/support/FullSupport.java b/game/core/src/main/java/net/minecraft/core/block/support/FullSupport.java
index 9a822344c..d72fe000b 100644
--- a/game/core/src/main/java/net/minecraft/core/block/support/FullSupport.java
+++ b/game/core/src/main/java/net/minecraft/core/block/support/FullSupport.java
@@ -1,14 +1,20 @@
 package net.minecraft.core.block.support;
 
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.NotNull;
 
 public class FullSupport implements ISupport {
-    public static final FullSupport INSTANCE = new FullSupport();
+    public static final @NotNull FullSupport INSTANCE = new FullSupport();
 
     private FullSupport() { }
 
     @Override
-    public boolean canSupport(final ISupport other, final Side side) {
+    public boolean canSupport(final @NotNull ISupport other, final @NotNull Side side) {
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "{Full-support}";
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/support/ISupport.java b/game/core/src/main/java/net/minecraft/core/block/support/ISupport.java
index 30819f84d..bb66a7e73 100644
--- a/game/core/src/main/java/net/minecraft/core/block/support/ISupport.java
+++ b/game/core/src/main/java/net/minecraft/core/block/support/ISupport.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.block.support;
 
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Used to indicate how one block can support another "hangable" block.
@@ -11,5 +12,5 @@ public interface ISupport {
      * @param other The block to check against.
      * @return Whether the block keyed by "other" can be hung.
      */
-    boolean canSupport(final ISupport other, final Side side);
+    boolean canSupport(final @NotNull ISupport other, final @NotNull Side side);
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/support/ISupportable.java b/game/core/src/main/java/net/minecraft/core/block/support/ISupportable.java
index f7fcb3828..5bb6c81dc 100644
--- a/game/core/src/main/java/net/minecraft/core/block/support/ISupportable.java
+++ b/game/core/src/main/java/net/minecraft/core/block/support/ISupportable.java
@@ -3,17 +3,18 @@ package net.minecraft.core.block.support;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
 
 public interface ISupportable {
-    ISupport getSupportConstraint(final World world, final int x, final int y, final int z, final Side side);
+    @NotNull ISupport getSupportConstraint(final @NotNull World world, final int x, final int y, final int z, final @NotNull Side side);
 
-    default boolean isSupported(final World world, final int x, final int y, final int z, final Side side) {
-        final Block<?> supportingBlock = world.getBlock(x, y, z);
+    default boolean isSupported(final @NotNull World world, final int x, final int y, final int z, final @NotNull Side side) {
+        final Block<?> supportingBlock = world.getBlock(x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ());
         if (supportingBlock == null) {
             return false;
         }
-        final ISupport supporting = supportingBlock.getSupport(world, x, y, z, side.getOpposite());
-        final ISupport supported = getSupportConstraint(world, x, y, z, side);
+        final ISupport supporting = supportingBlock.getSupport(world, x + side.getOffsetX(), y + side.getOffsetY(), z + side.getOffsetZ(), side.getOpposite());
+        final ISupport supported = this.getSupportConstraint(world, x, y, z, side);
         return supporting.canSupport(supported, side.getOpposite());
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/block/support/PartialSupport.java b/game/core/src/main/java/net/minecraft/core/block/support/PartialSupport.java
index f188faaa1..4708493ce 100644
--- a/game/core/src/main/java/net/minecraft/core/block/support/PartialSupport.java
+++ b/game/core/src/main/java/net/minecraft/core/block/support/PartialSupport.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.block.support;
 
 import net.minecraft.core.util.helper.Side;
+import org.jetbrains.annotations.NotNull;
 
 public class PartialSupport implements ISupport {
     private static final byte UP = 0b00001;
@@ -9,8 +10,8 @@ public class PartialSupport implements ISupport {
     private static final byte RIGHT = 0b01000;
     private static final byte CENTER = 0b10000;
 
-    public static final PartialSupport INSTANCE;
-    private static final PartialSupport[] PERMUTATIONS = new PartialSupport[32];
+    public static final @NotNull PartialSupport INSTANCE;
+    private static final @NotNull PartialSupport @NotNull [] PERMUTATIONS = new PartialSupport[32];
 
     static {
         for (int i = 0; i < 32; i++) {
@@ -25,28 +26,28 @@ public class PartialSupport implements ISupport {
         this.supportField = supportField;
     }
 
-    public PartialSupport up() {
+    public @NotNull PartialSupport up() {
         return PERMUTATIONS[this.supportField | UP];
     }
 
-    public PartialSupport down() {
+    public @NotNull PartialSupport down() {
         return PERMUTATIONS[this.supportField | DOWN];
     }
 
-    public PartialSupport left() {
+    public @NotNull PartialSupport left() {
         return PERMUTATIONS[this.supportField | LEFT];
     }
 
-    public PartialSupport right() {
+    public @NotNull PartialSupport right() {
         return PERMUTATIONS[this.supportField | RIGHT];
     }
 
-    public PartialSupport center() {
+    public @NotNull PartialSupport center() {
         return PERMUTATIONS[this.supportField | CENTER];
     }
 
     @Override
-    public boolean canSupport(final ISupport other, final Side side) {
+    public boolean canSupport(final @NotNull ISupport other, final @NotNull Side side) {
         if (other instanceof PartialSupport) {
             byte supportField = this.supportField;
             // Check if flip
@@ -61,10 +62,22 @@ public class PartialSupport implements ISupport {
                     supportField |= LEFT;
                 }
             }
-            PartialSupport partialOther = (PartialSupport) other;
+            final @NotNull PartialSupport partialOther = (PartialSupport) other;
             return (supportField & partialOther.supportField) == partialOther.supportField;
         } else {
             return false;
         }
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("{ Partial Support");
+        if ((this.supportField & UP) != 0) builder.append(", UP");
+        if ((this.supportField & DOWN) != 0) builder.append(", DOWN");
+        if ((this.supportField & LEFT) != 0) builder.append(", LEFT");
+        if ((this.supportField & RIGHT) != 0) builder.append(", RIGHT");
+        if ((this.supportField & CENTER) != 0) builder.append(", CENTER");
+        builder.append(" }");
+        return builder.toString();
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java b/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java
index 0c41ed3f4..fca80d65f 100644
--- a/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java
+++ b/game/core/src/main/java/net/minecraft/core/current/util/BlockState.java
@@ -5,6 +5,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.util.helper.Direction;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.World;
 
 public class BlockState {
@@ -87,8 +88,12 @@ public class BlockState {
 
 	public boolean canSurvive(World world, BlockPos pos) {
 		Block<?> block = world.getBlock(pos.x, pos.y, pos.z);
-		Block<?> underBlock = world.getBlock(pos.x, pos.y - 1, pos.z);
-		return (block == null || block == Blocks.WIRE_REDSTONE || block.getMaterial().isReplaceable()) && underBlock != null && underBlock.isCubeShaped();
+		if (block == Blocks.WIRE_REDSTONE) {
+            return Blocks.WIRE_REDSTONE.getLogic().isSupported(world, pos.x, pos.y, pos.z, Side.BOTTOM);
+		} else {
+			Block<?> underBlock = world.getBlock(pos.x, pos.y - 1, pos.z);
+			return (block == null || block.getMaterial().isReplaceable()) && underBlock != null && underBlock.isCubeShaped();
+		}
 	}
 
 	public void dropItems(World world, BlockPos pos) {
diff --git a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRule.java b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRule.java
index d43112870..2f6d3f82e 100644
--- a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRule.java
+++ b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRule.java
@@ -9,7 +9,7 @@ public abstract class GameRule<T>
     private final @NotNull String translationKey;
     private final T defaultValue;
 
-    public GameRule(final @NotNull String key, final @NotNull String translationKey, final T defaultValue)
+    public GameRule(final @NotNull String key, final @NotNull String translationKey, final @NotNull T defaultValue)
     {
         this.key = key;
         this.translationKey = translationKey;
@@ -25,7 +25,7 @@ public abstract class GameRule<T>
         return this.translationKey;
     }
 
-    public T getDefaultValue()
+    public @NotNull T getDefaultValue()
     {
         return this.defaultValue;
     }
diff --git a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
index 96b4ea68b..defc46d2a 100644
--- a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
+++ b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRuleCollection.java
@@ -2,6 +2,7 @@ package net.minecraft.core.data.gamerule;
 
 import com.mojang.nbt.tags.CompoundTag;
 import net.minecraft.core.data.registry.Registries;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -18,7 +19,7 @@ public final class GameRuleCollection
         }
     }
 
-    public <T> T getValue(GameRule<T> gameRule)
+    public <T> @NotNull T getValue(final @NotNull GameRule<T> gameRule)
     {
         Object o = gameRules.get(gameRule);
         if (o == null)
diff --git a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
index 1c1cb3b3e..73764f68c 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/animal/MobWolf.java
@@ -753,7 +753,7 @@ public class MobWolf
                 }
                 if(!world.isClientSide)
                 {
-                    if(random.nextInt(3) == 0)
+                    if(random.nextInt(3) == 0 || !player.getGamemode().consumeBlocks())
                     {
                         setWolfTamed(true);
                         setPathToEntity(null);
diff --git a/game/core/src/main/java/net/minecraft/core/item/IItemConvertible.java b/game/core/src/main/java/net/minecraft/core/item/IItemConvertible.java
index a8dd41b9a..38e44b9f5 100644
--- a/game/core/src/main/java/net/minecraft/core/item/IItemConvertible.java
+++ b/game/core/src/main/java/net/minecraft/core/item/IItemConvertible.java
@@ -1,7 +1,9 @@
 package net.minecraft.core.item;
 
+import org.jetbrains.annotations.NotNull;
+
 public interface IItemConvertible {
     Item asItem();
 
-    ItemStack getDefaultStack();
+    @NotNull ItemStack getDefaultStack();
 }
diff --git a/game/core/src/main/java/net/minecraft/core/item/Item.java b/game/core/src/main/java/net/minecraft/core/item/Item.java
index 695cd14de..2888c293c 100644
--- a/game/core/src/main/java/net/minecraft/core/item/Item.java
+++ b/game/core/src/main/java/net/minecraft/core/item/Item.java
@@ -338,7 +338,7 @@ public class Item implements ITaggable<Item>, IItemConvertible
     }
 
     @Override
-    public ItemStack getDefaultStack() {
+    public @NotNull ItemStack getDefaultStack() {
         return new ItemStack(this);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
index aa488e2c1..13757c6e0 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemDoor.java
@@ -1,7 +1,11 @@
 package net.minecraft.core.item;
 
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogicDoor;
 import net.minecraft.core.block.entity.TileEntityActivator;
+import net.minecraft.core.block.support.FullSupport;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
 import net.minecraft.core.util.helper.Direction;
@@ -13,10 +17,10 @@ import org.jetbrains.annotations.Nullable;
 import java.util.Random;
 
 public class ItemDoor extends Item {
-	protected final Block<?> doorBlockBottom;
-	protected final Block<?> doorBlockTop;
+	protected final Block<? extends BlockLogicDoor> doorBlockBottom;
+	protected final Block<? extends BlockLogicDoor> doorBlockTop;
 
-	public ItemDoor(String name, String namespaceId, int id, Block<?> doorBlockBottom, Block<?> doorBlockTop) {
+	public ItemDoor(String name, String namespaceId, int id, Block<? extends BlockLogicDoor> doorBlockBottom, Block<? extends BlockLogicDoor> doorBlockTop) {
 		super(name, namespaceId, id);
 		maxStackSize = 64;
         this.doorBlockBottom = doorBlockBottom;
@@ -30,31 +34,31 @@ public class ItemDoor extends Item {
 			blockY += side.getOffsetY();
 			blockZ += side.getOffsetZ();
 		}
-		if(!doorBlockBottom.canPlaceBlockAt(world, blockX, blockY, blockZ)) {
-			return false;
-		}
 
 		Direction dir = player.getHorizontalPlacementDirection(side).rotate(3);
 		int meta = dir.getHorizontalIndex();
-		
-		int xOffset = -dir.getOffsetX();
-		int zOffset = -dir.getOffsetZ();
 
-		int isSolidBlockLeft = (world.isBlockNormalCube(blockX - xOffset, blockY, blockZ - zOffset) ? 1 : 0) + (world.isBlockNormalCube(blockX - xOffset, blockY + 1, blockZ - zOffset) ? 1 : 0);
-		int isSolidBlockRight = (world.isBlockNormalCube(blockX + xOffset, blockY, blockZ + zOffset) ? 1 : 0) + (world.isBlockNormalCube(blockX + xOffset, blockY + 1, blockZ + zOffset) ? 1 : 0);
-		boolean isDoorLeft = world.getBlockId(blockX - xOffset, blockY, blockZ - zOffset) == doorBlockBottom.id() || world.getBlockId(blockX - xOffset, blockY + 1, blockZ - zOffset) == doorBlockTop.id();
-		boolean isDoorRight = world.getBlockId(blockX + xOffset, blockY, blockZ + zOffset) == doorBlockBottom.id() || world.getBlockId(blockX + xOffset, blockY + 1, blockZ + zOffset) == doorBlockTop.id();
+		int isSolidBlockLeft = (isSupported(world, blockX, blockY, blockZ, dir, false) ? 1 : 0) + (isSupported(world, blockX, blockY + 1, blockZ, dir, false) ? 1 : 0);
+		int isSolidBlockRight = (isSupported(world, blockX, blockY, blockZ, dir.getOpposite(), true) ? 1 : 0) + (isSupported(world, blockX, blockY + 1, blockZ, dir.getOpposite(), true) ? 1 : 0);
+		boolean isDoorLeft = world.getBlockId(blockX + dir.getOffsetX(), blockY, blockZ + dir.getOffsetZ()) == doorBlockBottom.id() || world.getBlockId(blockX + dir.getOffsetX(), blockY + 1, blockZ + dir.getOffsetZ()) == doorBlockTop.id();
+		boolean isDoorRight = world.getBlockId(blockX - dir.getOffsetX(), blockY, blockZ - dir.getOffsetZ()) == doorBlockBottom.id() || world.getBlockId(blockX - dir.getOffsetX(), blockY + 1, blockZ - dir.getOffsetZ()) == doorBlockTop.id();
 		boolean isMirrored = false;
 		
 		if(isDoorLeft && !isDoorRight) {
+			isMirrored = (world.getBlockMetadata(blockX + dir.getOffsetX(), blockY, blockZ + dir.getOffsetZ()) & BlockLogicDoor.MASK_HINGE) == 0;
+		} else if (isSolidBlockLeft > 0 && side.getDirection() == dir.getOpposite()) {
+		} else if (isSolidBlockRight > 0 && side.getDirection() == dir) {
 			isMirrored = true;
 		} else if(isSolidBlockRight > isSolidBlockLeft) {
 			isMirrored = true;
 		}
 		if(isMirrored) {
-			meta = meta - 1 & 3;
-			meta += 4;
-			meta |= 0x8;
+			meta = meta - 1 & 0b11;
+			meta |= 0b100;
+			meta |= 0b1000;
+		}
+		if(!doorBlockBottom.getLogic().canPlaceBlockAt(world, blockX, blockY, blockZ, meta)) {
+			return false;
 		}
 		
 		world.noNeighborUpdate = true;
@@ -70,6 +74,11 @@ public class ItemDoor extends Item {
 		return true;
 	}
 
+	public boolean isSupported(@NotNull World world, int x, int y, int z, @NotNull Direction direction, boolean mirrored) {
+		ISupport support = world.getSupport(x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ(), direction.getSide().getOpposite());
+		return support.canSupport(mirrored ? PartialSupport.INSTANCE.right() : PartialSupport.INSTANCE.left(), direction.getSide());
+	}
+
 	@Override
 	public void onUseByActivator(ItemStack itemStack, TileEntityActivator activatorBlock, World world, Random random, int blockX, int blockY, int blockZ, double offX, double offY, double offZ, Direction direction) {
 		if(!world.canPlaceInsideBlock(blockX, blockY, blockZ)) {
@@ -77,32 +86,29 @@ public class ItemDoor extends Item {
 			blockY += direction.getOffsetY();
 			blockZ += direction.getOffsetZ();
 		}
-		if(!doorBlockBottom.canPlaceBlockAt(world, blockX, blockY, blockZ)) {
-			return;
-		}
 
 		if (!direction.isHorizontal()) direction = Direction.NORTH;
 		Direction dir = direction.rotate(3);
 		int meta = dir.getHorizontalIndex();
 
-		int xOffset = -dir.getOffsetX();
-		int zOffset = -dir.getOffsetZ();
-
-		int isSolidBlockLeft = (world.isBlockNormalCube(blockX - xOffset, blockY, blockZ - zOffset) ? 1 : 0) + (world.isBlockNormalCube(blockX - xOffset, blockY + 1, blockZ - zOffset) ? 1 : 0);
-		int isSolidBlockRight = (world.isBlockNormalCube(blockX + xOffset, blockY, blockZ + zOffset) ? 1 : 0) + (world.isBlockNormalCube(blockX + xOffset, blockY + 1, blockZ + zOffset) ? 1 : 0);
-		boolean isDoorLeft = world.getBlockId(blockX - xOffset, blockY, blockZ - zOffset) == doorBlockBottom.id() || world.getBlockId(blockX - xOffset, blockY + 1, blockZ - zOffset) == doorBlockTop.id();
-		boolean isDoorRight = world.getBlockId(blockX + xOffset, blockY, blockZ + zOffset) == doorBlockBottom.id() || world.getBlockId(blockX + xOffset, blockY + 1, blockZ + zOffset) == doorBlockTop.id();
+		int isSolidBlockLeft = (world.isBlockNormalCube(blockX + dir.getOffsetX(), blockY, blockZ + dir.getOffsetZ()) ? 1 : 0) + (world.isBlockNormalCube(blockX + dir.getOffsetX(), blockY + 1, blockZ + dir.getOffsetZ()) ? 1 : 0);
+		int isSolidBlockRight = (world.isBlockNormalCube(blockX - dir.getOffsetX(), blockY, blockZ - dir.getOffsetZ()) ? 1 : 0) + (world.isBlockNormalCube(blockX - dir.getOffsetX(), blockY + 1, blockZ - dir.getOffsetZ()) ? 1 : 0);
+		boolean isDoorLeft = world.getBlockId(blockX + dir.getOffsetX(), blockY, blockZ + dir.getOffsetZ()) == doorBlockBottom.id() || world.getBlockId(blockX + dir.getOffsetX(), blockY + 1, blockZ + dir.getOffsetZ()) == doorBlockTop.id();
+		boolean isDoorRight = world.getBlockId(blockX - dir.getOffsetX(), blockY, blockZ - dir.getOffsetZ()) == doorBlockBottom.id() || world.getBlockId(blockX - dir.getOffsetX(), blockY + 1, blockZ - dir.getOffsetZ()) == doorBlockTop.id();
 		boolean isMirrored = false;
 
 		if(isDoorLeft && !isDoorRight) {
-			isMirrored = true;
+			isMirrored = (world.getBlockMetadata(blockX + dir.getOffsetX(), blockY, blockZ + dir.getOffsetZ()) & BlockLogicDoor.MASK_HINGE) == 0;
 		} else if(isSolidBlockRight > isSolidBlockLeft) {
 			isMirrored = true;
 		}
 		if(isMirrored) {
-			meta = meta - 1 & 3;
-			meta += 4;
-			meta |= 0x8;
+			meta = meta - 1 & 0b11;
+			meta |= 0b100;
+			meta |= 0b1000;
+		}
+		if(!doorBlockBottom.getLogic().canPlaceBlockAt(world, blockX, blockY, blockZ, meta)) {
+			return;
 		}
 
 		world.noNeighborUpdate = true;
@@ -116,4 +122,5 @@ public class ItemDoor extends Item {
 		doorBlockTop.onBlockPlacedOnSide(world, blockX, blockY + 1, blockZ, direction.getSide(), 0.5, 0.5);
 		itemStack.consumeItem(null);
 	}
+
 }
diff --git a/game/core/src/main/java/net/minecraft/core/item/ItemDoorPainted.java b/game/core/src/main/java/net/minecraft/core/item/ItemDoorPainted.java
index d950b8f5f..6eed035e1 100644
--- a/game/core/src/main/java/net/minecraft/core/item/ItemDoorPainted.java
+++ b/game/core/src/main/java/net/minecraft/core/item/ItemDoorPainted.java
@@ -1,6 +1,7 @@
 package net.minecraft.core.item;
 
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogicDoor;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
 import net.minecraft.core.util.helper.Direction;
@@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class ItemDoorPainted extends ItemDoor {
-    public ItemDoorPainted(String name, String namespaceId, int id, Block<?> doorBottom, Block<?> doorTopId) {
+    public ItemDoorPainted(String name, String namespaceId, int id, Block<? extends BlockLogicDoor> doorBottom, Block<? extends BlockLogicDoor> doorTopId) {
         super(name, namespaceId, id, doorBottom, doorTopId);
     }
     @Override
diff --git a/game/core/src/main/java/net/minecraft/core/util/Util.java b/game/core/src/main/java/net/minecraft/core/util/Util.java
new file mode 100644
index 000000000..20df90c85
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/util/Util.java
@@ -0,0 +1,14 @@
+package net.minecraft.core.util;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public final class Util {
+    public static @NotNull String emptyStringIfNull(final @Nullable String string) {
+        if (string == null) {
+            return "";
+        }
+
+        return string;
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/Side.java b/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
index a2c1faf97..cc33de425 100644
--- a/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
+++ b/game/core/src/main/java/net/minecraft/core/util/helper/Side.java
@@ -1,5 +1,7 @@
 package net.minecraft.core.util.helper;
 
+import org.jetbrains.annotations.NotNull;
+
 public enum Side {
 	
 	TOP(Axis.Y, 0, 1, 0, "top"),
@@ -95,7 +97,7 @@ public enum Side {
 		return offsetZ;
 	}
 	
-	public Side getOpposite() {
+	public @NotNull Side getOpposite() {
 		return opposite;
 	}
 	
diff --git a/game/core/src/main/java/net/minecraft/core/world/Dimension.java b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
index 85db03fd9..7df0f373a 100644
--- a/game/core/src/main/java/net/minecraft/core/world/Dimension.java
+++ b/game/core/src/main/java/net/minecraft/core/world/Dimension.java
@@ -10,6 +10,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.world.save.DimensionData;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.type.WorldTypes;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collections;
@@ -85,7 +86,7 @@ public class Dimension
 	public static final Dimension NETHER = new Dimension("nether", OVERWORLD, 0.125f, Blocks.PORTAL_NETHER, WorldTypes.NETHER_DEFAULT);
 	public static final Dimension DRIFT = new Dimension("drift", OVERWORLD, 8.0f, Blocks.PORTAL_DRIFT, WorldTypes.DRIFT_DEFAULT);
 
-	public static Int2ObjectMap<Dimension> getDimensionList() {
+	public static @NotNull Int2ObjectMap<Dimension> getDimensionList() {
 		return dimensionListUnmodifiable;
 	}
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/World.java b/game/core/src/main/java/net/minecraft/core/world/World.java
index 6e39f17b4..781685bde 100644
--- a/game/core/src/main/java/net/minecraft/core/world/World.java
+++ b/game/core/src/main/java/net/minecraft/core/world/World.java
@@ -14,6 +14,9 @@ import java.util.UUID;
 import com.mojang.logging.LogUtils;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.support.ISupport;
+import net.minecraft.core.block.support.ISupportable;
+import net.minecraft.core.block.support.PartialSupport;
 import net.minecraft.core.current.wire.WireHandler;
 import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.animal.MobFireflyCluster;
@@ -1661,7 +1664,7 @@ public class World implements WorldSource {
                 int id1 = getBlockId(entry.x, entry.y, entry.z);
                 if(id1 == entry.blockId && id1 > 0) {
                     immediatelyUpdatedPositions.add(entry);
-                    Blocks.blocksList[id1].updateTick(this, entry.x, entry.y, entry.z, rand);
+                    Blocks.blocksList[id1].updateTick(this, entry.x, entry.y, entry.z, rand, false);
                 }
             }
             return;
@@ -2229,6 +2232,12 @@ public class World implements WorldSource {
         }
     }
 
+    public @NotNull ISupport getSupport(int x, int y, int z, @NotNull Side side) {
+        Block<?> b = getBlock(x, y, z);
+        if (b == null) return PartialSupport.INSTANCE;
+        return b.getSupport(this, x, y, z, side);
+    }
+
     @Override
     public boolean isBlockNormalCube(int x, int y, int z)
     {
@@ -2445,7 +2454,7 @@ public class World implements WorldSource {
                     int iBlockY = (iRandVal / (ChunkSection.SECTION_SIZE_Y * Chunk.CHUNK_SIZE_Z * Chunk.CHUNK_SIZE_X)) & (ChunkSection.SECTION_SIZE_Y - 1) + s * ChunkSection.SECTION_SIZE_Y;
                     int id = chunk.getBlockID(iBlockX, iBlockY, iBlockZ);
                     if (Blocks.shouldTick[id]) {
-                        Blocks.blocksList[id].updateTick(this, iBlockX + chunkBlockX, iBlockY, iBlockZ + chunkBlockZ, this.rand);
+                        Blocks.blocksList[id].updateTick(this, iBlockX + chunkBlockX, iBlockY, iBlockZ + chunkBlockZ, this.rand, true);
                     }
                 }
             }
@@ -2481,7 +2490,7 @@ public class World implements WorldSource {
             int blockId = getBlockId(entry.x, entry.y, entry.z);
             if(blockId == entry.blockId && blockId > 0)
             {
-                Blocks.blocksList[blockId].updateTick(this, entry.x, entry.y, entry.z, rand);
+                Blocks.blocksList[blockId].updateTick(this, entry.x, entry.y, entry.z, rand, false);
             }
         }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfig.java b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfig.java
index 11ac99e7e..edc813b88 100644
--- a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfig.java
+++ b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfig.java
@@ -1,8 +1,10 @@
 package net.minecraft.core.world.config.season;
 
+import org.jetbrains.annotations.NotNull;
+
 public abstract class SeasonConfig
 {
-    public static SeasonConfigBuilder builder()
+    public static @NotNull SeasonConfigBuilder builder()
     {
         return new SeasonConfigBuilder();
     }
diff --git a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
index 951626226..89f9ff7b4 100644
--- a/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
+++ b/game/core/src/main/java/net/minecraft/core/world/config/season/SeasonConfigBuilder.java
@@ -3,6 +3,7 @@ package net.minecraft.core.world.config.season;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import net.minecraft.core.world.season.Season;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -22,7 +23,7 @@ public class SeasonConfigBuilder
 
     protected SeasonConfigBuilder() { }
 
-    public SeasonConfig build()
+    public @NotNull SeasonConfig build()
     {
         if (this.type == Type.SINGLE && this.singleSeason != null)
         {
@@ -38,7 +39,7 @@ public class SeasonConfigBuilder
         }
     }
 
-    public SeasonConfigBuilder withSingleSeason(final Season season)
+    public @NotNull SeasonConfigBuilder withSingleSeason(final Season season)
     {
         this.type = Type.SINGLE;
         this.seasons = null;
@@ -48,7 +49,7 @@ public class SeasonConfigBuilder
         return this;
     }
 
-    public SeasonConfigBuilder withSeasonInCycle(final Season season, final int length)
+    public @NotNull SeasonConfigBuilder withSeasonInCycle(final Season season, final int length)
     {
         this.type = Type.CYCLE;
         if (this.seasons == null) this.seasons = new ArrayList<>();
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecoration.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecoration.java
new file mode 100644
index 000000000..3b87cc68b
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkDecoration.java
@@ -0,0 +1,11 @@
+package net.minecraft.core.world.generate.chunk;
+
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public interface ChunkDecoration {
+    void placeDecoration(final @NotNull World world, final @NotNull Chunk chunk, final int worldX, final int worldZ, final int minY, final int maxY, final int rangeY, final @NotNull Random rand);
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
new file mode 100644
index 000000000..5f39eaa7d
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkFeatureDecorator.java
@@ -0,0 +1,73 @@
+package net.minecraft.core.world.generate.chunk;
+
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import net.minecraft.core.block.BlockLogic;
+import net.minecraft.core.block.BlockLogicSand;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+public abstract class ChunkFeatureDecorator
+    implements ChunkDecorator
+{
+    private boolean initialized = false;
+    private final @NotNull World world;
+    private final @NotNull Object2IntMap<ChunkDecoration> decorations = new Object2IntOpenHashMap<>();
+
+    public ChunkFeatureDecorator(final @NotNull World world) {
+        this.world = world;
+    }
+
+    /* package-private */ final void registerDecorationsSetup() {
+        if (!this.initialized) {
+            this.registerDecorations();
+            this.initialized = true;
+        }
+    }
+
+    public abstract void registerDecorations();
+
+    public final @NotNull ChunkFeatureDecorator register(final int seed, final @NotNull ChunkDecoration decoration) {
+        this.decorations.put(decoration, seed);
+
+        return this;
+    }
+
+    @Override
+    public final void decorate(final @NotNull Chunk chunk) {
+        this.world.scheduledUpdatesAreImmediate = true;
+        BlockLogicSand.fallInstantly = true;
+
+        final int chunkX = chunk.xPosition;
+        final int chunkZ = chunk.zPosition;
+        final int worldX = chunkX * 16;
+        final int worldZ = chunkZ * 16;
+
+        final int minY = this.world.getWorldType().getMinY();
+        final int maxY = this.world.getWorldType().getMaxY();
+        final int rangeY = (maxY + 1) - minY;
+
+        final @NotNull Random rand = new Random(this.world.getRandomSeed());
+        final long a = (rand.nextLong() / 2L) * 2L + 1L;
+        final long b = (rand.nextLong() / 2L) * 2L + 1L;
+
+        for (final @NotNull ChunkDecoration decoration : this.decorations.keySet()) {
+            final int decorationSeed = this.decorations.getInt(decoration);
+            rand.setSeed((long) chunkX * a + (long) chunkZ * b ^ this.world.getRandomSeed() ^ decorationSeed);
+            decoration.placeDecoration(this.world, chunk, worldX, worldZ, minY, maxY, rangeY, rand);
+        }
+
+        this.postDecorate(this.world, chunk);
+
+        BlockLogicSand.fallInstantly = false;
+        this.world.scheduledUpdatesAreImmediate = false;
+    }
+
+    public abstract void postDecorate(final @NotNull World world, final @NotNull Chunk chunk);
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkGenerator.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkGenerator.java
index 404380849..70e0c3e58 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkGenerator.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/ChunkGenerator.java
@@ -65,7 +65,6 @@ public abstract class ChunkGenerator
         ChunkGeneratorResult result = doBlockGeneration(chunk);
 
         // Slice up blocks
-        int blocksInSection = CHUNK_SIZE_X * SECTION_SIZE_Y * CHUNK_SIZE_Z;
         for (int sectionY = 0; sectionY < Chunk.CHUNK_SECTIONS; sectionY++) {
             ChunkSection section = chunk.getSection(sectionY);
             section.blocks = result.getSectionBlocks(sectionY);
@@ -83,6 +82,10 @@ public abstract class ChunkGenerator
      */
     public final void decorate(Chunk chunk)
     {
+        if (decorator instanceof ChunkFeatureDecorator) {
+            ((ChunkFeatureDecorator) decorator).registerDecorationsSetup();
+        }
+
         decorator.decorate(chunk);
     }
 
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index 8ccca75ff..63a25d670 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -584,6 +584,36 @@ public class ChunkDecoratorOverworld
             (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, i22, l23, i25);
         }
 
+        int numPebbles = 0;
+        if (biome == Biomes.OVERWORLD_FOREST) {
+            numPebbles = 2;
+        }
+        if (biome == Biomes.OVERWORLD_SWAMPLAND) {
+            numPebbles = 2;
+        }
+        if (biome == Biomes.OVERWORLD_GRASSLANDS) {
+            numPebbles = 2;
+        }
+        if (biome == Biomes.OVERWORLD_PLAINS || biome == Biomes.OVERWORLD_SHRUBLAND) {
+            numPebbles = 3;
+        }
+        if (biome == Biomes.OVERWORLD_CAATINGA || biome == Biomes.OVERWORLD_CAATINGA_PLAINS) {
+            numPebbles = 5;
+        }
+        if (biome == Biomes.OVERWORLD_OUTBACK_GRASSY || biome == Biomes.OVERWORLD_OUTBACK) {
+            numPebbles = 2;
+        }
+        if (biome == Biomes.OVERWORLD_DESERT) {
+            numPebbles = 5;
+        }
+
+        for (int i = 0; i < numPebbles; i++) {
+            final int xx = x + rand.nextInt(16) + 8;
+            final int yy = minY + rand.nextInt(rangeY);
+            final int zz = z + rand.nextInt(16) + 8;
+            (new WorldFeaturePebbles(Blocks.OVERLAY_PEBBLES.id(), 16, true)).place(this.world, rand, xx, yy, zz);
+        }
+
         int oceanY = world.getWorldType().getOceanY();
         for(int dx = x + 8; dx < x + 8 + 16; dx++)
         {
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
index 293c58a70..52c6c1440 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/hell/ChunkDecoratorOverworldHell.java
@@ -11,239 +11,233 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.chunk.Chunk;
 import net.minecraft.core.world.generate.chunk.ChunkDecorator;
+import net.minecraft.core.world.generate.chunk.ChunkFeatureDecorator;
 import net.minecraft.core.world.generate.feature.*;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree;
 import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy;
 import net.minecraft.core.world.noise.PerlinNoise;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
 public class ChunkDecoratorOverworldHell
-    implements ChunkDecorator
-{
-    private final World world;
+    extends ChunkFeatureDecorator {
     private final PerlinNoise treeDensityNoise;
 
-    public ChunkDecoratorOverworldHell(World world)
-    {
-        this.world = world;
-
-        treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74);
+    public ChunkDecoratorOverworldHell(final @NotNull World world) {
+        super(world);
+        this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74);
     }
 
     @Override
-    public void decorate(Chunk chunk)
-    {
-        int chunkX = chunk.xPosition;
-        int chunkZ = chunk.zPosition;
-
-        int minY = world.getWorldType().getMinY();
-        int maxY = world.getWorldType().getMaxY();
-        int rangeY = (maxY + 1) - minY;
-
-//        float oreHeightModifier = rangeY / 128f;
-
-        BlockLogicSand.fallInstantly = true;
-        int x = chunkX * 16;
-        int z = chunkZ * 16;
-//        int y = world.getHeightValue(x + 16, z + 16);
-//        Biome biome = world.getBlockBiome(x + 16, y, z + 16);
-        Random rand = new Random(world.getRandomSeed());
-        long l1 = (rand.nextLong() / 2L) * 2L + 1L;
-        long l2 = (rand.nextLong() / 2L) * 2L + 1L;
-        rand.setSeed((long)chunkX * l1 + (long) chunkZ * l2 ^ world.getRandomSeed());
-        if(rand.nextInt(32) == 0)
-        {
-            int i1 = x + rand.nextInt(16) + 8;
-            int l4 = minY + rand.nextInt(rangeY);
-            int i8 = z + rand.nextInt(16) + 8;
-            (new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id())).place(world, rand, i1, l4, i8);
-        }
-        if(rand.nextInt(16) == 0)
-        {
-            int j1 = x + rand.nextInt(16) + 8;
-            int i5 = minY + rand.nextInt(rangeY - 16) + 8;
-            int j8 = z + rand.nextInt(16) + 8;
-
-            if(i5 < minY + rangeY / 2 || rand.nextInt(10) == 0)
-            {
-                if(rand.nextInt(4) == 0)
-                {
-                    (new WorldFeatureLake(Blocks.OBSIDIAN.id())).place(world, rand, j1, i5, j8);
-                }
-                else
-                {
-                    (new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id())).place(world, rand, j1, i5, j8);
+    public void registerDecorations() {
+        this.register(0, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            if (rand.nextInt(32) == 0) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                (new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id())).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(1, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            if (rand.nextInt(16) == 0) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rangeY - 16) + 8;
+                final int zz = worldZ + rand.nextInt(16) + 8;
+
+                if (yy < minY + rangeY / 2 || rand.nextInt(10) == 0) {
+                    if (rand.nextInt(4) == 0) {
+                        (new WorldFeatureLake(Blocks.OBSIDIAN.id())).place(world, rand, xx, yy, zz);
+                    } else {
+                        (new WorldFeatureLake(Blocks.FLUID_LAVA_STILL.id())).place(world, rand, xx, yy, zz);
+                    }
                 }
             }
-        }
-
-        for(int l18 = 0; l18 < 50; l18++)
-        {
-            int l21 = x + rand.nextInt(16) + 8;
-            int k23 = minY + rand.nextInt(rangeY / 2);
-            int l24 = z + rand.nextInt(16) + 8;
-            if(k23 < minY + rangeY / 2) {
-                (new WorldFeatureLiquid(Blocks.FLUID_WATER_FLOWING.id())).place(world, rand, l21, k23, l24);
+        });
+
+        this.register(2, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 50; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rangeY / 2);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                if (yy < minY + rangeY / 2) {
+                    (new WorldFeatureLiquid(Blocks.FLUID_WATER_FLOWING.id())).place(world, rand, xx, yy, zz);
+                }
             }
-        }
-        for(int k1 = 0; k1 < 8; k1++)
-        {
-            int j5 = x + rand.nextInt(16) + 8;
-            int k8 = minY + rand.nextInt(rangeY);
-            int j11 = z + rand.nextInt(16) + 8;
-            if (rand.nextInt(2) == 0)
-            {
-                (new WorldFeatureDungeon(Blocks.BRICK_CLAY.id(), Blocks.BRICK_CLAY.id(), null)).place(world, rand, j5, k8, j11);
-            }
-            else
-            {
-                (new WorldFeatureDungeon(Blocks.COBBLE_STONE.id(), Blocks.COBBLE_STONE_MOSSY.id(), null)).place(world, rand, j5, k8, j11);
+        });
+
+        this.register(3, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 8; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                if (rand.nextInt(2) == 0) {
+                    (new WorldFeatureDungeon(Blocks.BRICK_CLAY.id(), Blocks.BRICK_CLAY.id(), null)).place(world, rand, xx, yy, zz);
+                } else {
+                    (new WorldFeatureDungeon(Blocks.COBBLE_STONE.id(), Blocks.COBBLE_STONE_MOSSY.id(), null)).place(world, rand, xx, yy, zz);
+                }
             }
-        }
+        });
 
-        for(int k1 = 0; k1 < 1; k1++)
-        {
-            int j5 = x + rand.nextInt(16) + 8;
-            int j11 = z + rand.nextInt(16) + 8;
-            int k8 = world.getHeightValue(j5, j11) - (rand.nextInt(2)+2);
+        this.register(4, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 1; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                int yy = world.getHeightValue(xx, zz) - (rand.nextInt(2) + 2);
 
-            //chance to sink labyrinth
-            if(rand.nextInt(10)==0)
-                k8 -= rand.nextInt(10)+30;
+                //chance to sink labyrinth
+                if (rand.nextInt(10) == 0)
+                    yy -= rand.nextInt(10) + 30;
 
-            if(rand.nextInt(512) == 0) {
-                (new WorldFeatureLabyrinth()).place(world, rand, j5, k8, j11);
+                if (rand.nextInt(512) == 0) {
+                    (new WorldFeatureLabyrinth()).place(world, rand, xx, yy, zz);
+                }
             }
-        }
-
-        for(int i2 = 0; i2 < 20; i2++)
-        {
-            int k5 = x + rand.nextInt(16);
-            int l8 = minY + rand.nextInt(rangeY);
-            int k11 = z + rand.nextInt(16);
-            (new WorldFeatureClay(32)).place(world, rand, k5, l8, k11);
-        }
-
-        for(int j2 = 0; j2 < 20; j2++)
-        {
-            int l5 = x + rand.nextInt(16);
-            int i9 = minY + rand.nextInt(rangeY);
-            int l11 = z + rand.nextInt(16);
-            (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(world, rand, l5, i9, l11);
-        }
-
-        for(int k2 = 0; k2 < 10; k2++)
-        {
-            int i6 = x + rand.nextInt(16);
-            int j9 = minY + rand.nextInt(rangeY);
-            int i12 = z + rand.nextInt(16);
-            (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(world, rand, i6, j9, i12);
-        }
-
-        for(int i3 = 0; i3 < 20; i3++)
-        {
-            int j6 = x + rand.nextInt(16);
-            int k9 = minY + rand.nextInt(rangeY);
-            int j12 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(world, rand, j6, k9, j12);
-        }
-
-        for(int j3 = 0; j3 < 20; j3++)
-        {
-            int k6 = x + rand.nextInt(16);
-            int l9 = minY + rand.nextInt(rangeY / 2);
-            int k12 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(world, rand, k6, l9, k12);
-        }
-
-        for(int k3 = 0; k3 < 2; k3++)
-        {
-            int l6 = x + rand.nextInt(16);
-            int i10 = minY + rand.nextInt(rangeY / 4);
-            int l12 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(world, rand, l6, i10, l12);
-        }
-
-        for(int l3 = 0; l3 < 8; l3++)
-        {
-            int i7 = x + rand.nextInt(16);
-            int j10 = minY + rand.nextInt(rangeY / 8);
-            int i13 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(world, rand, i7, j10, i13);
-        }
-
-        for(int i4 = 0; i4 < 1; i4++)
-        {
-            int j7 = x + rand.nextInt(16);
-            int k10 = minY + rand.nextInt(rangeY / 8);
-            int j13 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(world, rand, j7, k10, j13);
-        }
-
-        for(int j4 = 0; j4 < 1; j4++)
-        {
-            int k7 = x + rand.nextInt(16);
-            int l10 = minY + rand.nextInt(rangeY / 8) + rand.nextInt(rangeY / 8);
-            int k13 = z + rand.nextInt(16);
-            (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(world, rand, k7, l10, k13);
-        }
-
-        double d = 0.5D;
-        int treeDensity = (int)((treeDensityNoise.get((double)x * d, (double)z * d) / 8D + rand.nextDouble() * 4D + 4D) / 3D);
-        if(rand.nextInt(10) == 0)
-        {
-            treeDensity++;
-        }
-        treeDensity /= 2;
-        for(int i11 = 0; i11 < treeDensity; i11++)
-        {
-            boolean hasLeaves = rand.nextInt(1234) == 0;
-            int l13 = x + rand.nextInt(16) + 8;
-            int j14 = z + rand.nextInt(16) + 8;
-            WorldFeature wf;
-            if(rand.nextInt(10) == 0)
-            {
-                wf = new WorldFeatureTreeFancy(hasLeaves ? Blocks.LEAVES_OAK.id() : 0, Blocks.LOG_OAK.id());
-            } else
-            {
-                wf = new WorldFeatureTree(hasLeaves ? Blocks.LEAVES_OAK.id() : 0, Blocks.LOG_OAK.id(), 4);
-            }
-            wf.init(1.0D, 1.0D, 1.0D);
-            wf.place(world, rand, l13, world.getHeightValue(l13, j14), j14);
-        }
+        });
+
+        this.register(5, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 20; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldX + rand.nextInt(16);
+                (new WorldFeatureClay(32)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(6, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 20; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(Blocks.DIRT.id(), 32)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(7, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 10; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(Blocks.GRAVEL.id(), 32)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(8, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 20; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreCoal.variantMap, 16)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(9, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 20; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY / 2);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreIron.variantMap, 8)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(10, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 2; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY / 4);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreGold.variantMap, 8)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(11, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 8; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY / 8);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreRedstone.variantMap, 7)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(12, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 1; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY / 8);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreDiamond.variantMap, 7)).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(13, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 1; i++) {
+                final int xx = worldX + rand.nextInt(16);
+                final int yy = minY + rand.nextInt(rangeY / 8) + rand.nextInt(rangeY / 8);
+                final int zz = worldZ + rand.nextInt(16);
+                (new WorldFeatureOre(BlockLogicOreLapis.variantMap, 6)).place(world, rand, xx, yy, zz);
+            }
+        });
 
-        byte byte1 = 10;
-        for(int i15 = 0; i15 < byte1; i15++)
-        {
-            int i17 = x + rand.nextInt(16) + 8;
-            int i20 = minY + rand.nextInt(rangeY);
-            int l22 = z + rand.nextInt(16) + 8;
-            (new WorldFeatureDeadBush(Blocks.DEADBUSH.id())).place(world, rand, i17, i20, l22);
-        }
+        this.register(14, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            final double d = 0.5D;
+            int treeDensity = (int) ((this.treeDensityNoise.get((double) worldX * d, (double) worldZ * d) / 8D + rand.nextDouble() * 4D + 4D) / 3D);
+            if (rand.nextInt(10) == 0) {
+                treeDensity++;
+            }
+            treeDensity /= 2;
+            for (int i = 0; i < treeDensity; i++) {
+                final boolean hasLeaves = rand.nextInt(1234) == 0;
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                final WorldFeature wf;
+                if (rand.nextInt(10) == 0) {
+                    wf = new WorldFeatureTreeFancy(hasLeaves ? Blocks.LEAVES_OAK.id() : 0, Blocks.LOG_OAK.id());
+                } else {
+                    wf = new WorldFeatureTree(hasLeaves ? Blocks.LEAVES_OAK.id() : 0, Blocks.LOG_OAK.id(), 4);
+                }
+                wf.init(1.0D, 1.0D, 1.0D);
+                wf.place(world, rand, xx, world.getHeightValue(xx, zz), zz);
+            }
+        });
+
+        this.register(15, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 10; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rangeY);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                (new WorldFeatureDeadBush(Blocks.DEADBUSH.id())).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(16, (world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 5; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rand.nextInt(rangeY - 8) + 8);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, xx, yy, zz);
+            }
+        });
+
+        this.register(17, ((world, chunk, worldX, worldZ, minY, maxY, rangeY, rand) -> {
+            for (int i = 0; i < 20; i++) {
+                final int xx = worldX + rand.nextInt(16) + 8;
+                final int yy = minY + rand.nextInt(rand.nextInt(rand.nextInt(rangeY - rangeY / 8) + 8) + 8);
+                final int zz = worldZ + rand.nextInt(16) + 8;
+                (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, xx, yy, zz);
+            }
+        }));
+    }
 
-        for(int l18 = 0; l18 < 5; l18++)
-        {
-            int l21 = x + rand.nextInt(16) + 8;
-            int k23 = minY + rand.nextInt(rand.nextInt(rangeY - 8) + 8);
-            int l24 = z + rand.nextInt(16) + 8;
-            (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, l21, k23, l24);
-        }
+    @Override
+    public void postDecorate(@NotNull final World world, @NotNull final Chunk chunk) {
+        final int chunkX = chunk.xPosition;
+        final int chunkZ = chunk.zPosition;
+        final int worldX = chunkX * 16;
+        final int worldZ = chunkZ * 16;
 
-        for(int i19 = 0; i19 < 20; i19++)
-        {
-            int i22 = x + rand.nextInt(16) + 8;
-            int l23 = minY + rand.nextInt(rand.nextInt(rand.nextInt(rangeY - rangeY / 8) + 8) + 8);
-            int i25 = z + rand.nextInt(16) + 8;
-            (new WorldFeatureLiquid(Blocks.FLUID_LAVA_FLOWING.id())).place(world, rand, i22, l23, i25);
-        }
+        final int minY = world.getWorldType().getMinY();
 
-        if (world.getBlockId(x, minY + world.getWorldType().getOceanY() - 1, z) == world.getWorldType().getOceanBlockId())
-        {
-            world.setBlockWithNotify(x, minY + world.getWorldType().getOceanY() - 1, z, world.getWorldType().getOceanBlockId());
+        if (world.getBlockId(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ) == world.getWorldType().getOceanBlockId()) {
+            world.setBlockWithNotify(worldX, minY + world.getWorldType().getOceanY() - 1, worldZ, world.getWorldType().getOceanBlockId());
         }
-
-        BlockLogicSand.fallInstantly = false;
-
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLiquid.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLiquid.java
index 8dfb139ab..47d2a78bd 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLiquid.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureLiquid.java
@@ -66,7 +66,7 @@ public class WorldFeatureLiquid extends WorldFeature
         {
             world.setBlockWithNotify(x, y, z, liquidBlockId);
             world.scheduledUpdatesAreImmediate = true;
-            Blocks.blocksList[liquidBlockId].updateTick(world, x, y, z, random);
+            Blocks.blocksList[liquidBlockId].updateTick(world, x, y, z, random, false);
             world.scheduledUpdatesAreImmediate = false;
         }
         return true;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java
index 565b7a070..e9b913193 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureNetherLava.java
@@ -71,7 +71,7 @@ public class WorldFeatureNetherLava extends WorldFeature
         {
             world.setBlockWithNotify(x, y, z, blockId);
             world.scheduledUpdatesAreImmediate = true;
-            Blocks.blocksList[blockId].updateTick(world, x, y, z, random);
+            Blocks.blocksList[blockId].updateTick(world, x, y, z, random, false);
             world.scheduledUpdatesAreImmediate = false;
         }
         return true;
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePebbles.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePebbles.java
new file mode 100644
index 000000000..299061d6c
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePebbles.java
@@ -0,0 +1,64 @@
+package net.minecraft.core.world.generate.feature;
+
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogicFlowerStackable;
+import net.minecraft.core.block.BlockLogicOverlayPebbles;
+import net.minecraft.core.block.Blocks;
+import net.minecraft.core.world.World;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public class WorldFeaturePebbles extends WorldFeature {
+    private final int blockId;
+    private final int count;
+    private final boolean varyStackSize;
+
+    @MethodParametersAnnotation(names = { "blockId", "count", "varyStackSize" })
+    public WorldFeaturePebbles(final int blockId, final int count, final boolean varyStackSize) {
+        this.blockId = blockId;
+        this.count = count;
+        this.varyStackSize = varyStackSize;
+    }
+
+    @Override
+    public boolean place(final @NotNull World world, final @NotNull Random random, final int x, final int y, final int z) {
+        for (int i = 0; i < this.count; i++) {
+            final int xx = (x + random.nextInt(8)) - random.nextInt(8);
+            final int yy = (y + random.nextInt(4)) - random.nextInt(4);
+            final int zz = (z + random.nextInt(8)) - random.nextInt(8);
+            if (world.isAirBlock(xx, yy, zz) && BlockLogicOverlayPebbles.canSpawnOn(world.getBlock(xx, yy - 1, zz))) {
+                final int metadata;
+                if (Block.hasLogicClass(Blocks.getBlock(this.blockId), BlockLogicOverlayPebbles.class)) {
+                    final int stackSize;
+                    if (this.varyStackSize) {
+                        stackSize = getStackSize(random);
+                    } else {
+                        stackSize = 0;
+                    }
+
+                    metadata = BlockLogicFlowerStackable.setStackCount(0, stackSize);
+                } else {
+                    metadata = 0;
+                }
+                world.setBlockAndMetadata(xx, yy, zz, this.blockId, metadata);
+            }
+        }
+
+        return true;
+    }
+
+    private static int getStackSize(final @NotNull Random random) {
+        // 0 = 0-7 (8 chances)
+        // 1 = 8-13 (6 chances)
+        // 2 = 14-17 (4 chances)
+        final int odds = random.nextInt(18);
+        if (odds < 8) {
+            return 0;
+        } else if (odds < 14) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+}
diff --git a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePillar.java b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePillar.java
index bcdf2cbff..fc3810948 100644
--- a/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePillar.java
+++ b/game/core/src/main/java/net/minecraft/core/world/generate/feature/WorldFeaturePillar.java
@@ -101,7 +101,7 @@ public class WorldFeaturePillar
                 if (world.getBlockId(x - largerRadius + rx, y0 + ry, z - largerRadius + rz) == Blocks.COBBLE_NETHERRACK.id()) {
                     world.setBlockWithNotify(x - largerRadius + rx, y0 + ry, z - largerRadius + rz, Blocks.FLUID_LAVA_FLOWING.id());
                     world.scheduledUpdatesAreImmediate = true;
-                    Blocks.FLUID_LAVA_FLOWING.updateTick(world, x - largerRadius + rx, y0 + ry, z - largerRadius + rz, random);
+                    Blocks.FLUID_LAVA_FLOWING.updateTick(world, x - largerRadius + rx, y0 + ry, z - largerRadius + rz, random, false);
                     world.scheduledUpdatesAreImmediate = false;
                 }
             }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
index 1c7425b77..8fd2dce1c 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldType.java
@@ -12,6 +12,7 @@ import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.Weathers;
 import net.minecraft.core.world.wind.WindProvider;
 import net.minecraft.core.world.wind.WindProviderGeneric;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Random;
 
@@ -260,36 +261,36 @@ public abstract class WorldType {
             this.languageKey = languageKey;
         }
 
-        public static Properties of(String languageKey) {
+        public static @NotNull Properties of(String languageKey) {
             return new Properties(languageKey);
         }
 
-        public Properties defaultWeather(Weather weather) {
+        public @NotNull Properties defaultWeather(Weather weather) {
             this.defaultWeather = weather;
             return this;
         }
 
-        public Properties windManager(WindProvider windProvider) {
+        public @NotNull Properties windManager(WindProvider windProvider) {
             this.windProvider = windProvider;
             return this;
         }
 
-        public Properties withCeiling() {
+        public @NotNull Properties withCeiling() {
             this.hasCeiling = true;
             return this;
         }
 
-        public Properties brightnessRamp(float[] brightnessRamp) {
+        public @NotNull Properties brightnessRamp(float[] brightnessRamp) {
             this.brightnessRamp = brightnessRamp;
             return this;
         }
 
-        public Properties seasonConfig(SeasonConfig seasonConfig) {
+        public @NotNull Properties seasonConfig(SeasonConfig seasonConfig) {
             this.seasonConfig = seasonConfig;
             return this;
         }
 
-        public Properties bounds(int minY, int maxY, int oceanY) {
+        public @NotNull Properties bounds(int minY, int maxY, int oceanY) {
             if (minY < 0) {
                 throw new IllegalArgumentException("minY cannot be negative");
             }
@@ -310,7 +311,7 @@ public abstract class WorldType {
             return this;
         }
 
-        public Properties portalBounds(int minPortalY, int maxPortalY) {
+        public @NotNull Properties portalBounds(int minPortalY, int maxPortalY) {
             if (minPortalY < 0) {
                 throw new IllegalArgumentException("minPortalY cannot be negative");
             }
@@ -325,27 +326,27 @@ public abstract class WorldType {
             return this;
         }
 
-        public Properties oceanBlock(Block<?> oceanBlock) {
+        public @NotNull Properties oceanBlock(Block<?> oceanBlock) {
             this.oceanBlock = oceanBlock;
             return this;
         }
 
-        public Properties fillerBlock(Block<?> fillerBlock) {
+        public @NotNull Properties fillerBlock(Block<?> fillerBlock) {
             this.fillerBlock = fillerBlock;
             return this;
         }
 
-        public Properties dayNightCycleTicks(int ticks) {
+        public @NotNull Properties dayNightCycleTicks(int ticks) {
             this.dayNightCycleTicks = ticks;
             return this;
         }
 
-        public Properties allowRespawn() {
+        public @NotNull Properties allowRespawn() {
             this.mayRespawn = true;
             return this;
         }
 
-        public Properties setRetro() {
+        public @NotNull Properties setRetro() {
             this.isRetro = true;
             return this;
         }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
index 6045382e0..a5e9c23db 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypeGroups.java
@@ -1,15 +1,13 @@
 package net.minecraft.core.world.type;
 
 import net.minecraft.core.world.Dimension;
+import org.jetbrains.annotations.NotNull;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class WorldTypeGroups {
-    public static final List<Group> GROUPS = new ArrayList<>();
-    public static final Group DEFAULT = new Group(WorldTypes.OVERWORLD_EXTENDED);
+    public static final @NotNull List<@NotNull Group> GROUPS = new ArrayList<>();
+    public static final @NotNull Group DEFAULT = new Group(WorldTypes.OVERWORLD_EXTENDED);
 
     static {
         GROUPS.add(
@@ -73,16 +71,19 @@ public class WorldTypeGroups {
         private final Map<Dimension, WorldType> worldTypes = new HashMap<>();
 
         public Group(WorldType overworldType) {
-            worldTypes.put(Dimension.OVERWORLD, overworldType);
+            for (int i = 0; i < Dimension.getDimensionList().size(); i++) {
+                this.worldTypes.put(Dimension.getDimensionList().get(i), Objects.requireNonNull(Dimension.getDimensionList().get(i)).defaultWorldType);
+            }
+            this.worldTypes.put(Dimension.OVERWORLD, overworldType);
         }
 
-        public Group with(Dimension dimension, WorldType worldType) {
-            worldTypes.put(dimension, worldType);
+        public @NotNull Group with(Dimension dimension, WorldType worldType) {
+            this.worldTypes.put(dimension, worldType);
             return this;
         }
 
-        public WorldType get(Dimension dimension) {
-            return worldTypes.get(dimension);
+        public @NotNull WorldType get(Dimension dimension) {
+            return Objects.requireNonNull(this.worldTypes.get(dimension));
         }
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
index 67f4d3df5..d2960163b 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/WorldTypes.java
@@ -9,15 +9,16 @@ import net.minecraft.core.world.type.nether.WorldTypeNetherSkyblock;
 import net.minecraft.core.world.type.overworld.*;
 import net.minecraft.core.world.type.drift.WorldTypeDrift;
 import net.minecraft.core.world.weather.Weathers;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class WorldTypes {
-    public static final WorldType OVERWORLD_EXTENDED = register(
+    public static final @NotNull WorldType OVERWORLD_EXTENDED = register(
             "minecraft:overworld.extended",
             new WorldTypeOverworld(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.extended")
             )
     );
-    public static final WorldType OVERWORLD_DEFAULT = register(
+    public static final @NotNull WorldType OVERWORLD_DEFAULT = register(
             "minecraft:overworld.default",
             new WorldTypeOverworld(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.default")
@@ -25,27 +26,27 @@ public abstract class WorldTypes {
                             .portalBounds(0, 255)
             )
     );
-    public static final WorldType NETHER_DEFAULT = register(
+    public static final @NotNull WorldType NETHER_DEFAULT = register(
             "minecraft:nether.default",
             new WorldTypeNether(
                     WorldTypeNether.defaultProperties("worldType.nether.default")
                         .portalBounds(127, 255)
             )
     );
-    public static final WorldType NETHER_SKYBLOCK = register(
+    public static final @NotNull WorldType NETHER_SKYBLOCK = register(
             "minecraft:nether.skyblock",
             new WorldTypeNetherSkyblock(
                     WorldTypeNether.defaultProperties("worldType.nether.skyblock")
                         .bounds(0, 127, 0)
             )
     );
-    public static final WorldType DRIFT_DEFAULT = register(
+    public static final @NotNull WorldType DRIFT_DEFAULT = register(
             "minecraft:drift.default",
             new WorldTypeDrift(
                     WorldTypeDrift.defaultProperties("worldType.drift.default")
             )
     );
-    public static final WorldType FLAT = register(
+    public static final @NotNull WorldType FLAT = register(
             "minecraft:flat",
             new WorldTypeFlat(
                     WorldType.Properties.of("worldType.flat")
@@ -60,7 +61,7 @@ public abstract class WorldTypes {
                             )
             )
     );
-    public static final WorldType OVERWORLD_FLOATING = register(
+    public static final @NotNull WorldType OVERWORLD_FLOATING = register(
             "minecraft:overworld.floating",
             new WorldTypeOverworldFloating(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.floating")
@@ -68,14 +69,14 @@ public abstract class WorldTypes {
                             .oceanBlock(null)
             )
     );
-    public static final WorldType OVERWORLD_AMPLIFIED = register(
+    public static final @NotNull WorldType OVERWORLD_AMPLIFIED = register(
             "minecraft:overworld.amplified",
             new WorldTypeOverworld(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.amplified")
                             .bounds(0, 255, 64)
             )
     );
-    public static final WorldType OVERWORLD_RETRO = register(
+    public static final @NotNull WorldType OVERWORLD_RETRO = register(
             "minecraft:overworld.retro",
             new WorldTypeOverworldRetro(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.retro")
@@ -85,14 +86,14 @@ public abstract class WorldTypes {
                             .setRetro()
             )
     );
-    public static final WorldType OVERWORLD_ISLANDS = register(
+    public static final @NotNull WorldType OVERWORLD_ISLANDS = register(
             "minecraft:overworld.islands",
             new WorldTypeOverworld(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.islands")
                             .bounds(0, 255, 160)
             )
     );
-    public static final WorldType OVERWORLD_WINTER = register(
+    public static final @NotNull WorldType OVERWORLD_WINTER = register(
             "minecraft:overworld.winter",
             new WorldTypeOverworld(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.winter")
@@ -104,7 +105,7 @@ public abstract class WorldTypes {
                             .portalBounds(0, 255)
             )
     );
-    public static final WorldType OVERWORLD_HELL = register(
+    public static final @NotNull WorldType OVERWORLD_HELL = register(
             "minecraft:overworld.hell",
             new WorldTypeOverworldHell(
                     WorldType.Properties.of("worldType.overworld.hell")
@@ -121,14 +122,14 @@ public abstract class WorldTypes {
                             .defaultWeather(Weathers.OVERWORLD_HELL_CLEAR)
             )
     );
-    public static final WorldType OVERWORLD_WOODS = register(
+    public static final @NotNull WorldType OVERWORLD_WOODS = register(
             "minecraft:overworld.woods",
             new WorldTypeOverworldWoods(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.woods")
                             .defaultWeather(Weathers.OVERWORLD_WOODS_CLEAR)
             )
     );
-    public static final WorldType OVERWORLD_PARADISE = register(
+    public static final @NotNull WorldType OVERWORLD_PARADISE = register(
             "minecraft:overworld.paradise",
             new WorldTypeOverworldParadise(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.paradise")
@@ -140,7 +141,7 @@ public abstract class WorldTypes {
                             .portalBounds(0, 255)
             )
     );
-    public static final WorldType OVERWORLD_INLAND = register(
+    public static final @NotNull WorldType OVERWORLD_INLAND = register(
             "minecraft:overworld.inland",
             new WorldTypeOverworldInland(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.inland")
@@ -148,7 +149,7 @@ public abstract class WorldTypes {
                             .oceanBlock(null)
             )
     );
-    public static final WorldType OVERWORLD_CLASSIC = register(
+    public static final @NotNull WorldType OVERWORLD_CLASSIC = register(
             "minecraft:overworld.classic",
             new WorldTypeOverworldClassic(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.classic")
@@ -158,7 +159,7 @@ public abstract class WorldTypes {
                             .setRetro()
             )
     );
-    public static final WorldType OVERWORLD_INDEV = register(
+    public static final @NotNull WorldType OVERWORLD_INDEV = register(
             "minecraft:overworld.indev",
             new WorldTypeOverworldIndev(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.indev")
@@ -168,7 +169,7 @@ public abstract class WorldTypes {
                             .setRetro()
             )
     );
-    public static final WorldType OVERWORLD_SKYBLOCK = register(
+    public static final @NotNull WorldType OVERWORLD_SKYBLOCK = register(
             "minecraft:overworld.skyblock",
             new WorldTypeOverworldSkyblock(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.skyblock")
@@ -176,14 +177,14 @@ public abstract class WorldTypes {
                         .portalBounds(0, 255)
             )
     );
-    public static final WorldType OVERWORLD_BETA_173 = register(
+    public static final @NotNull WorldType OVERWORLD_BETA_173 = register(
             "minecraft:overworld.beta_173",
             new WorldTypeOverworldB173(
                     WorldTypeOverworld.defaultProperties("worldType.overworld.beta_173")
                             .bounds(0, 127, 64)
             )
     );
-    public static final WorldType EMPTY = register(
+    public static final @NotNull WorldType EMPTY = register(
             "minecraft:empty",
             new WorldTypeEmpty(
                     WorldType.Properties.of("worldType.empty")
@@ -192,7 +193,7 @@ public abstract class WorldTypes {
                             .allowRespawn()
             )
     );
-    public static final WorldType DEBUG = register(
+    public static final @NotNull WorldType DEBUG = register(
             "minecraft:debug",
             new WorldTypeDebug(
                     WorldType.Properties.of("worldType.debug")
@@ -202,7 +203,7 @@ public abstract class WorldTypes {
             )
     );
 
-    public static WorldType register(String key, WorldType worldType) {
+    public static @NotNull WorldType register(final @NotNull String key, final @NotNull WorldType worldType) {
         Registries.WORLD_TYPES.register(key, worldType);
 
         return worldType;
diff --git a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
index cb7050017..04e0c4070 100644
--- a/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
+++ b/game/core/src/main/java/net/minecraft/core/world/type/overworld/WorldTypeOverworld.java
@@ -11,6 +11,7 @@ import net.minecraft.core.world.generate.chunk.perlin.overworld.ChunkGeneratorOv
 import net.minecraft.core.world.season.Seasons;
 import net.minecraft.core.world.type.WorldType;
 import net.minecraft.core.world.weather.Weather;
+import org.jetbrains.annotations.NotNull;
 
 public class WorldTypeOverworld
         extends WorldType {
@@ -25,7 +26,7 @@ public class WorldTypeOverworld
         world.setWorldTime(72000 + 3000);
     }
 
-    public static Properties defaultProperties(String translationKey) {
+    public static @NotNull Properties defaultProperties(@NotNull String translationKey) {
         return Properties.of(translationKey)
                 .brightnessRamp(createLightRamp())
                 .seasonConfig(SeasonConfig.builder()
diff --git a/game/core/src/main/resources/lang/en_US/options.lang b/game/core/src/main/resources/lang/en_US/options.lang
index 4cac9c938..55afa489d 100644
--- a/game/core/src/main/resources/lang/en_US/options.lang
+++ b/game/core/src/main/resources/lang/en_US/options.lang
@@ -179,6 +179,7 @@ options.chatVisibility.show_all=Always Show
 options.chatVisibility.show_when_chatting=Only Show When Chatting
 options.chatVisibility.never_show=Never Show
 options.developerMode=Developer Mode
+options.viewSupportMode=View Supports
 options.devModels=Show Developer Models
 options.forceOnscreenKeyboard=Force On Screen Keyboard
 options.enableHolidayTextures=Enable Holiday Textures
diff --git a/util/datagen/build.gradle.kts b/util/datagen/build.gradle.kts
index 70d2ee8d4..9f0a275e2 100644
--- a/util/datagen/build.gradle.kts
+++ b/util/datagen/build.gradle.kts
@@ -21,7 +21,7 @@ val output by configurations.creating
 //region Tasks
 val runDatagen by tasks.registering(JavaExec::class) {
     group = "bta.generator"
-    val datagenDir = project.layout.buildDirectory.dir("generated/sources/datagen/resources")
+    val datagenDir = project.layout.buildDirectory.dir("resources/main")
     val recipesDir = datagenDir.get().file("recipes")
     outputs.dir(datagenDir)
 
