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 cf695d47a..2383491e3 100644
--- a/game/client/src/main/java/net/minecraft/client/Minecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/Minecraft.java
@@ -29,6 +29,10 @@ import net.minecraft.client.gui.toasts.GuiElementToastsHud;
 import net.minecraft.client.holiday.Holidays;
 import net.minecraft.client.net.handler.PacketHandlerClient;
 import net.minecraft.client.render.block.model.BlockModelGrass;
+import net.minecraft.client.render.font.FontDefault;
+import net.minecraft.client.render.font.FontMonospace;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.FontRendererDefault;
 import net.minecraft.client.world.WorldClient;
 import net.minecraft.client.world.chunk.provider.ChunkProviderStatic;
 import net.minecraft.core.achievement.Achievements;
@@ -78,6 +82,7 @@ import javax.swing.JOptionPane;
 
 import net.minecraft.client.gui.subtitles.SubtitleTracker;
 import net.minecraft.client.sound.SoundRepository;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import org.lwjgl.LWJGLException;
@@ -108,7 +113,6 @@ import net.minecraft.client.player.controller.PlayerController;
 import net.minecraft.client.render.ParticleEngine;
 import net.minecraft.client.render.EntityRenderDispatcher;
 import net.minecraft.client.render.FallbackRenderer;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.ItemRenderer;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.LoadingScreenRenderer;
@@ -218,8 +222,8 @@ public class Minecraft
     public String minecraftUri;
     public boolean hideQuitButton;
     public volatile boolean isGamePaused;
-    public TextureManager textureManager;
-    public Font font;
+    public final @NotNull TextureManager textureManager;
+    public final @NotNull FontRenderer font;
     /**
      * Current gui the player is looking at
      * is null when in a world during normal play
@@ -228,23 +232,22 @@ public class Minecraft
     public LoadingScreenRenderer loadingScreen;
     public WorldRenderer worldRenderer;
     public ThreadDownloadResources downloadResourcesThread;
-    private int ticksRan;
+    public int ticksRan;
     public GuiElementToastsHud guiToasts;
     public HudIngame hudIngame;
     public boolean skipRenderWorld;
     public HitResult objectMouseOver;
-    public GameSettings gameSettings;
+    public final @NotNull GameSettings gameSettings;
     public SoundEngine sndManager;
-    public final SubtitleTracker subtitleTracker = new SubtitleTracker();
-    public TexturePackList texturePackList;
-    private File mcDataDir;
+    public final @NotNull SubtitleTracker subtitleTracker = new SubtitleTracker();
+    public final @NotNull TexturePackList texturePackList;
+    private final @NotNull File mcDataDir;
     private ISaveFormat saveFormat;
     public static int numRecordedFrameTimes = 0;
     public static long hasPaidCheckTime = 0L;
     public StatsCounter statsCounter;
     private String serverName;
     private int serverPort;
-    private static File minecraftDir = null;
     public volatile boolean running;
     public String debug;
     public String debugFPS;
@@ -284,7 +287,7 @@ public class Minecraft
      * Keep this as the only constructor in this class for now,
      * otherwise JVM class verification will fail and the game will crash when the fabric loader tries to run the game.
      */
-    public Minecraft(GameWindow gameWindow, boolean test)
+    public Minecraft(final @NotNull File mcDataDir, final GameWindow gameWindow, final boolean test)
     {
         Global.accessor = this;
         hasCrashed = false;
@@ -306,6 +309,12 @@ public class Minecraft
         joinPlayerCounter = 0;
         INSTANCE = this;
 
+        this.mcDataDir = mcDataDir;
+        this.gameSettings = new GameSettings(this, mcDataDir);
+        this.texturePackList = new TexturePackList(this, this.mcDataDir);
+        this.textureManager = new TextureManager(this, this.texturePackList, this.gameSettings);
+        this.font = new FontRendererDefault(new FontDefault(this.textureManager));
+
         if(test) return;
 
         this.gameWindow = gameWindow;
@@ -456,7 +465,6 @@ public class Minecraft
     public void startGame() throws LWJGLException
     {
         ImageIO.setUseCache(false); // Speeds up boot time
-		mcDataDir = getMinecraftDir();
 
         // Initialize LogMessageReceiver to capture output
         LogMessageReceiver.init();
@@ -472,7 +480,7 @@ public class Minecraft
         CommandHelper.init();
         initCommands();
 
-		gameSettings = new GameSettings(this, mcDataDir);
+        this.gameSettings.init();
 
         LOGGER.info("Java Version: {}", System.getProperty("java.version"));
 
@@ -523,10 +531,9 @@ public class Minecraft
             setRenderer(new FallbackRenderer(this));
         }
 
-        texturePackList = new TexturePackList(this, mcDataDir);
-        textureManager = new TextureManager(this, texturePackList, gameSettings);
+        this.texturePackList.init();
 
-        TooltipElement.reloadStyles(texturePackList);
+        TooltipElement.reloadStyles(this.texturePackList);
         SoundRepository.initialize(this);
 
         // Show load screen as early as possible
@@ -795,13 +802,8 @@ public class Minecraft
         tessellator.draw();
     }
 
-    public File getMinecraftDir()
-    {
-        if(minecraftDir == null)
-        {
-            minecraftDir = getAppDir("minecraft-bta");
-        }
-        return minecraftDir;
+    public File getMinecraftDir() {
+        return this.mcDataDir;
     }
 
     @Override
@@ -1206,7 +1208,7 @@ public class Minecraft
 						}
 					}
 				}else {
-					hudIngame.addChatMessage(ScreenShot.saveScreenshot(minecraftDir, gameWindow.getWidthPixels(), gameWindow.getHeightPixels()));
+					hudIngame.addChatMessage(ScreenShot.saveScreenshot(getMinecraftDir(), gameWindow.getWidthPixels(), gameWindow.getHeightPixels()));
 				}
 				Debug.pop();
 			}
@@ -2624,10 +2626,10 @@ public class Minecraft
         this.renderer.reload();
     }
 
-    public static void startMainThread(@Nullable String username, @Nullable String sessionId, @Nullable String uuid, @Nullable String server, @Nullable Integer port, @Nullable Integer width, @Nullable Integer height)
+    public static void startMainThread(@Nullable String username, @Nullable String sessionId, @Nullable String uuid, @Nullable String server, @Nullable Integer port, @Nullable Integer width, @Nullable Integer height, @Nullable File mcDataDir)
     {
         GameWindow gameWindow = new GameWindowGLFW();
-        Minecraft mc = new Minecraft(gameWindow,false);
+        Minecraft mc = new Minecraft(mcDataDir == null ? getAppDir("minecraft-bta"): mcDataDir, gameWindow,false);
         mc.minecraftUri = "www.minecraft.net";
 
         sessionId = sessionId == null ? "" : sessionId;
@@ -2666,7 +2668,7 @@ public class Minecraft
 
         String playerName = null;
         String sessionId = null;
-        String gameDirectory = null;
+        File gameDirectory = null;
         String uuid = null;
         String server = null;
         Integer port = null;
@@ -2708,7 +2710,7 @@ public class Minecraft
                 }
                 case "--gameDir": {
                     try {
-                        minecraftDir = new File(args[pointer + 1]);
+                        gameDirectory = new File(args[pointer + 1]);
                         pointer++;
                     } catch (Exception e) {
                         e.printStackTrace();
@@ -2760,7 +2762,7 @@ public class Minecraft
                     pointer++;
             }
         }
-        startMainThread(playerName, sessionId, uuid, server, port, width, height);
+        startMainThread(playerName, sessionId, uuid, server, port, width, height, gameDirectory);
     }
     
     public void setInputType(InputType inputType) {
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 5e8331a98..2ec3b471e 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
@@ -1,12 +1,9 @@
 package net.minecraft.client.gui;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.window.CursorShape;
-import net.minecraft.client.render.window.GameWindowGLFW;
 import org.jetbrains.annotations.Nullable;
-import org.lwjgl.glfw.GLFW;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
@@ -87,7 +84,6 @@ public class ButtonElement extends Gui implements GuiElement
     {
         if (!visible) return;
 
-        Font font = mc.font;
         boolean mouseOver = mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height;
         int state = getButtonState(mouseOver);
 
@@ -125,7 +121,7 @@ public class ButtonElement extends Gui implements GuiElement
                 textColor = 0xFFFFA0;
                 break;
         }
-        drawStringCentered(font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
+        drawStringCenteredShadow(mc.font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
     }
 
     public boolean isHovered(int mouseX, int mouseY)
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ClickableLabelElement.java b/game/client/src/main/java/net/minecraft/client/gui/ClickableLabelElement.java
index cd24b7bca..868eabf83 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ClickableLabelElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ClickableLabelElement.java
@@ -1,8 +1,8 @@
 package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.window.CursorShape;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL11;
 
 public class ClickableLabelElement extends ButtonElement
@@ -62,14 +62,13 @@ public class ClickableLabelElement extends ButtonElement
             mc.currentScreen.setDesiredCursor(CursorShape.HAND);
         }
 
-        Font font = mc.font;
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-        width = font.getStringWidth(displayString) + 4;
+        width = MathHelper.ceil(mc.font.stringWidthDouble(displayString)) + 4;
         drawRect(xPosition, yPosition, xPosition + width, yPosition + height, enabled ? (hovered ? 0x7F8080C0 : bgColor) : 0x00000000);
         if (enabled && (shadow || hovered)) {
-            font.drawStringWithShadow(displayString, xPosition + 2, yPosition + 2, hovered ? 0xFFFFA0 : textColor);
+            drawStringShadow(mc.font, displayString, xPosition + 2, yPosition + 2, hovered ? 0xFFFFA0 : textColor);
         } else {
-            font.drawString(displayString, xPosition + 2, yPosition + 2, 0x7F7F7F);
+            drawStringNoShadow(mc.font, displayString, xPosition + 2, yPosition + 2, 0x7F7F7F);
         }
         mouseDragged(mc, mouseX, mouseY);
     }
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 21ffbd4e9..768e35691 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
@@ -7,11 +7,8 @@ import net.minecraft.client.gui.popup.PopupCloseListener;
 import net.minecraft.core.Global;
 import net.minecraft.core.net.command.TextFormatting;
 import org.lwjgl.Sys;
-import org.lwjgl.glfw.GLFW;
 import org.lwjgl.opengl.GL11;
 
-import java.awt.*;
-import java.awt.datatransfer.StringSelection;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Map;
@@ -54,7 +51,7 @@ public class ExceptionPopupElement {
 
 
         PopupScreen popup = new PopupBuilder(parent,860/scale).withLabel("gui.exception.label.exception_occurred")
-                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.getCharWidth('m'))
+                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.charWidth('m'))
                 .withButtonGroup("gui.exception.choice",new String[]{"gui.exception.button.back","gui.exception.button.copy_error"},new int[]{0,1})
                 .withOnCloseListener(new PopupListener(mc,s.toString().replaceAll("§[0-9a-f|klmnor]","")))
                 .build();
@@ -98,7 +95,7 @@ public class ExceptionPopupElement {
         ScreenBlank screen = new ScreenBlank();
         mc.displayScreen(screen);
         PopupScreen popup = new PopupBuilder(screen,860/scale).withLabel("gui.exception.label.fatal_error")
-                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.getCharWidth('m'))
+                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.charWidth('m'))
                 .withButtonGroup("gui.exception.choice",new String[]{"gui.exception.button.copy_error","gui.exception.button.copy_error_and_quit"},new int[]{0,2},new boolean[]{false,true})
                 .withBackgroundColor(0xff402020, 0xff501010)
                 .withOnCloseListener(new PopupListener(mc,s.toString().replaceAll("§[0-9a-f|klmnor]","")))
@@ -143,7 +140,7 @@ public class ExceptionPopupElement {
         ScreenBlank screen = new ScreenBlank();
         mc.displayScreen(screen);
         PopupScreen popup = new PopupBuilder(screen,860/scale).withLabel("gui.exception.label.startup_error")
-                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.getCharWidth('m'))
+                .withMessageBox("gui.exception.list",400/scale,s.toString(),(860/scale) / mc.font.charWidth('m'))
                 .withButtonGroup("gui.exception.choice",new String[]{"gui.exception.button.copy_error","gui.exception.button.copy_error_and_quit"},new int[]{0,2},new boolean[]{false,true})
                 .withBackgroundColor(0xff402020, 0xff501010)
                 .withOnCloseListener(new PopupListener(mc,s.toString().replaceAll("§[0-9a-f|klmnor]","")))
diff --git a/game/client/src/main/java/net/minecraft/client/gui/Gui.java b/game/client/src/main/java/net/minecraft/client/gui/Gui.java
index 355a19db6..b3abca07c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/Gui.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/Gui.java
@@ -2,15 +2,16 @@ package net.minecraft.client.gui;
 
 import static org.lwjgl.opengl.GL11.*;
 
-import net.minecraft.core.lang.text.Text;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.texture.Texture;
 import net.minecraft.client.render.texture.meta.gui.GuiTextureProperties;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 
 import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 import java.util.Objects;
@@ -20,144 +21,144 @@ public class Gui
 
     public Gui()
     {
-        zLevel = 0.0F;
+        this.zLevel = 0.0F;
     }
 
-    protected void drawLineHorizontal(int minX, int maxX, int minY, int argb)
+    protected void drawLineHorizontal(int minX, int maxX, final int minY, final int argb)
     {
         if(maxX < minX)
         {
-            int temp = minX;
+            final int temp = minX;
             minX = maxX;
             maxX = temp;
         }
         drawRect(minX, minY, maxX + 1, minY + 1, argb);
     }
 
-    protected void drawLineHorizontalDouble(double minX, double maxX, double minY, int argb)
+    protected void drawLineHorizontalDouble(double minX, double maxX, final double minY, final int argb)
     {
         if(maxX < minX)
         {
-            double temp = minX;
+            final double temp = minX;
             minX = maxX;
             maxX = temp;
         }
         drawRectDouble(minX, minY, maxX + 1, minY + 1, argb);
     }
 
-    protected void drawLineVertical(int minX, int minY, int maxY, int argb)
+    protected void drawLineVertical(final int minX, int minY, int maxY, final int argb)
     {
         if(maxY < minY)
         {
-            int temp = minY;
+            final int temp = minY;
             minY = maxY;
             maxY = temp;
         }
         drawRect(minX, minY + 1, minX + 1, maxY, argb);
     }
 
-    protected void drawLineVerticalDouble(double minX, double minY, double maxY, int argb)
+    protected void drawLineVerticalDouble(final double minX, double minY, double maxY, final int argb)
     {
         if(maxY < minY)
         {
-            double temp = minY;
+            final double temp = minY;
             minY = maxY;
             maxY = temp;
         }
         drawRectDouble(minX, minY + 1, minX + 1, maxY, argb);
     }
 
-    public void drawRect(int minX, int minY, int maxX, int maxY, int argb)
+    public void drawRect(int minX, int minY, int maxX, int maxY, final int argb)
     {
         if(minX < maxX)
         {
-            int temp = minX;
+            final int temp = minX;
             minX = maxX;
             maxX = temp;
         }
         if(minY < maxY)
         {
-            int temp = minY;
+            final int temp = minY;
             minY = maxY;
             maxY = temp;
         }
-        float a = (float)(argb >> 24 & 0xff) / 255F;
-        float r = (float)(argb >> 16 & 0xff) / 255F;
-        float g = (float)(argb >> 8 & 0xff) / 255F;
-        float b = (float)(argb & 0xff) / 255F;
-        Tessellator tessellator = Tessellator.instance;
+        final float a = (float)(argb >> 24 & 0xff) / 255F;
+        final float r = (float)(argb >> 16 & 0xff) / 255F;
+        final float g = (float)(argb >> 8 & 0xff) / 255F;
+        final float b = (float)(argb & 0xff) / 255F;
+        final Tessellator tessellator = Tessellator.instance;
         GL11.glEnable(GL_BLEND);
         GL11.glDisable(GL_TEXTURE_2D);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         GL11.glColor4f(r, g, b, a);
         tessellator.startDrawingQuads();
-        tessellator.addVertex(minX, maxY, zLevel);
-        tessellator.addVertex(maxX, maxY, zLevel);
-        tessellator.addVertex(maxX, minY, zLevel);
-        tessellator.addVertex(minX, minY, zLevel);
+        tessellator.addVertex(minX, maxY, this.zLevel);
+        tessellator.addVertex(maxX, maxY, this.zLevel);
+        tessellator.addVertex(maxX, minY, this.zLevel);
+        tessellator.addVertex(minX, minY, this.zLevel);
         tessellator.draw();
         GL11.glEnable(GL_TEXTURE_2D);
         GL11.glDisable(GL_BLEND);
     }
-    protected void drawRectDouble(double minX, double minY, double maxX, double maxY, int argb)
+    protected void drawRectDouble(double minX, double minY, double maxX, double maxY, final int argb)
     {
         if(minX < maxX)
         {
-            double temp = minX;
+            final double temp = minX;
             minX = maxX;
             maxX = temp;
         }
         if(minY < maxY)
         {
-            double temp = minY;
+            final double temp = minY;
             minY = maxY;
             maxY = temp;
         }
-        float a = (float)(argb >> 24 & 0xff) / 255F;
-        float r = (float)(argb >> 16 & 0xff) / 255F;
-        float g = (float)(argb >> 8 & 0xff) / 255F;
-        float b = (float)(argb & 0xff) / 255F;
-        Tessellator tessellator = Tessellator.instance;
+        final float a = (float)(argb >> 24 & 0xff) / 255F;
+        final float r = (float)(argb >> 16 & 0xff) / 255F;
+        final float g = (float)(argb >> 8 & 0xff) / 255F;
+        final float b = (float)(argb & 0xff) / 255F;
+        final Tessellator tessellator = Tessellator.instance;
         GL11.glEnable(GL_BLEND);
         GL11.glDisable(GL_TEXTURE_2D);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         GL11.glColor4f(r, g, b, a);
         tessellator.startDrawingQuads();
-        tessellator.addVertex(minX, maxY, zLevel);
-        tessellator.addVertex(maxX, maxY, zLevel);
-        tessellator.addVertex(maxX, minY, zLevel);
-        tessellator.addVertex(minX, minY, zLevel);
+        tessellator.addVertex(minX, maxY, this.zLevel);
+        tessellator.addVertex(maxX, maxY, this.zLevel);
+        tessellator.addVertex(maxX, minY, this.zLevel);
+        tessellator.addVertex(minX, minY, this.zLevel);
         tessellator.draw();
         GL11.glEnable(GL_TEXTURE_2D);
         GL11.glDisable(GL_BLEND);
     }
 
-    protected void drawBox(int minX, int minY, int maxX, int maxY, int argb, int lineThickness) {
+    protected void drawBox(final int minX, final int minY, final int maxX, final int maxY, final int argb, final int lineThickness) {
         drawRect(minX, minY, maxX, minY + lineThickness, argb);
         drawRect(minX, maxY - lineThickness, maxX, maxY, argb);
         drawRect(minX, minY + lineThickness, minX + lineThickness, maxY - lineThickness, argb);
         drawRect(maxX - lineThickness, minY + lineThickness, maxX, maxY - lineThickness, argb);
     }
 
-    protected void drawRectNoBlend(int minX, int minY, int maxX, int maxY, int argb)
+    protected void drawRectNoBlend(int minX, int minY, int maxX, int maxY, final int argb)
     {
         if(minX < maxX)
         {
-            int temp = minX;
+            final int temp = minX;
             minX = maxX;
             maxX = temp;
         }
         if(minY < maxY)
         {
-            int temp = minY;
+            final int temp = minY;
             minY = maxY;
             maxY = temp;
         }
-        float a = (float)(argb >> 24 & 0xff) / 255F;
-        float r = (float)(argb >> 16 & 0xff) / 255F;
-        float g = (float)(argb >> 8 & 0xff) / 255F;
-        float b = (float)(argb & 0xff) / 255F;
-        Tessellator tessellator = Tessellator.instance;
+        final float a = (float)(argb >> 24 & 0xff) / 255F;
+        final float r = (float)(argb >> 16 & 0xff) / 255F;
+        final float g = (float)(argb >> 8 & 0xff) / 255F;
+        final float b = (float)(argb & 0xff) / 255F;
+        final Tessellator tessellator = Tessellator.instance;
         GL11.glDisable(GL_TEXTURE_2D);
         GL11.glColor4f(r, g, b, a);
         tessellator.startDrawingQuads();
@@ -169,14 +170,14 @@ public class Gui
         GL11.glEnable(GL_TEXTURE_2D);
     }
     
-    protected void drawRectWidthHeight(int x, int y, int width, int height, int argb) {
-    	float a = ((argb >> 24) & 0xFF) / 255f;
-    	float r = ((argb >> 16) & 0xFF) / 255f;
-    	float g = ((argb >>  8) & 0xFF) / 255f;
-    	float b = ((argb >>  0) & 0xFF) / 255f;
+    protected void drawRectWidthHeight(final int x, final int y, final int width, final int height, final int argb) {
+    	final float a = ((argb >> 24) & 0xFF) / 255f;
+    	final float r = ((argb >> 16) & 0xFF) / 255f;
+    	final float g = ((argb >>  8) & 0xFF) / 255f;
+    	final float b = ((argb >>  0) & 0xFF) / 255f;
     	glColor4f(r, g, b, a);
     	glDisable(GL_TEXTURE_2D);
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
         tessellator.addVertex(x, y, 0);
         tessellator.addVertex(x, y+height, 0);
@@ -186,22 +187,22 @@ public class Gui
         glEnable(GL_TEXTURE_2D);
     }
 
-    protected void drawGradientRect(int minX, int minY, int maxX, int maxY, int argb1, int argb2)
+    protected void drawGradientRect(final int minX, final int minY, final int maxX, final int maxY, final int argb1, final int argb2)
     {
-        float a1 = (float)(argb1 >> 24 & 0xff) / 255F;
-        float r1 = (float)(argb1 >> 16 & 0xff) / 255F;
-        float g1 = (float)(argb1 >> 8 & 0xff) / 255F;
-        float b1 = (float)(argb1 & 0xff) / 255F;
-        float a2 = (float)(argb2 >> 24 & 0xff) / 255F;
-        float r2 = (float)(argb2 >> 16 & 0xff) / 255F;
-        float g2 = (float)(argb2 >> 8 & 0xff) / 255F;
-        float b2 = (float)(argb2 & 0xff) / 255F;
+        final float a1 = (float)(argb1 >> 24 & 0xff) / 255F;
+        final float r1 = (float)(argb1 >> 16 & 0xff) / 255F;
+        final float g1 = (float)(argb1 >> 8 & 0xff) / 255F;
+        final float b1 = (float)(argb1 & 0xff) / 255F;
+        final float a2 = (float)(argb2 >> 24 & 0xff) / 255F;
+        final float r2 = (float)(argb2 >> 16 & 0xff) / 255F;
+        final float g2 = (float)(argb2 >> 8 & 0xff) / 255F;
+        final float b2 = (float)(argb2 & 0xff) / 255F;
         GL11.glDisable(GL_TEXTURE_2D);
         GL11.glEnable(GL_BLEND);
         GL11.glDisable(GL_ALPHA_TEST);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         GL11.glShadeModel(GL_SMOOTH);
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
         tessellator.setColorRGBA_F(r1, g1, b1, a1);
         tessellator.addVertex(maxX, minY, 0.0D);
@@ -216,203 +217,183 @@ public class Gui
         GL11.glEnable(GL_TEXTURE_2D);
     }
 
-    public void drawTextCentered(Font fr, Text text, int x, int y, int argb)
-    {
-        fr.drawTextWithShadow(text, x - fr.getTextWidth(text) / 2, y, argb);
-    }
-
-    public void drawTextCenteredNoShadow(Font fr, Text text, int x, int y, int argb)
-    {
-        fr.drawText(text, x - fr.getTextWidth(text) / 2, y, argb);
+    public void drawStringCenteredShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
+        FontHelper.renderCentered(Tessellator.instance, chars, x, y).setZ(this.zLevel).setShadow().setColor(argb).call(fontRenderer);
     }
-
-    public void drawText(Font fr, Text text, int x, int y, int argb)
-    {
-        fr.drawTextWithShadow(text, x, y, argb);
-    }
-
-    public void drawTextNoShadow(Font fr, Text text, int x, int y, int argb)
-    {
-        fr.drawText(text, x, y, argb);
+    
+    public void drawStringCenteredNoShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
+        FontHelper.renderCentered(Tessellator.instance, chars, x, y).setZ(this.zLevel).setColor(argb).call(fontRenderer);
     }
 
-    public void drawStringCentered(Font fr, String string, int x, int y, int argb)
-    {
-        fr.drawStringWithShadow(string, x - fr.getStringWidth(string) / 2, y, argb);
+    public void drawStringShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
+        FontHelper.render(Tessellator.instance, chars, x, y).setZ(this.zLevel).setShadow().setColor(argb).call(fontRenderer);
     }
     
-    public void drawStringCenteredNoShadow(Font fr, String string, int x, int y, int argb)
-    {
-        fr.drawString(string, x - fr.getStringWidth(string) / 2, y, argb);
+    public void drawStringNoShadow(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int argb) {
+        FontHelper.render(Tessellator.instance, chars, x, y).setZ(this.zLevel).setColor(argb).call(fontRenderer);
     }
 
-    public void drawString(Font fr, String string, int x, int y, int argb)
-    {
-        fr.drawStringWithShadow(string, x, y, argb);
-    }
-    
-    public void drawStringNoShadow(Font fr, String string, int x, int y, int argb)
-    {
-    	fr.drawString(string, x, y, argb);
+    public void drawStringConstrained(final @NotNull FontRenderer fontRenderer, final @NotNull CharSequence chars, final int x, final int y, final int maxWidth, final int argb) {
+        FontHelper.renderWidthConstrained(Tessellator.instance, chars, x, y, maxWidth).setZ(this.zLevel).setColor(argb).call(fontRenderer);
     }
 
-    public void drawTexturedModalRect(int x, int y, int u, int v, int width, int height)
+    public void drawTexturedModalRect(final int x, final int y, final int u, final int v, final int width, final int height)
     {
-        float uScale = 0.00390625F;
-        float vScale = 0.00390625F;
-        Tessellator tessellator = Tessellator.instance;
+        final float uScale = 0.00390625F;
+        final float vScale = 0.00390625F;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x + 0, y + height, zLevel, (u + 0) * uScale, (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width, y + height, zLevel, (u + width) * uScale, (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width, y + 0, zLevel, (u + width) * uScale, (v + 0) * vScale);
-        tessellator.addVertexWithUV(x + 0, y + 0, zLevel, (u + 0) * uScale, (v + 0) * vScale);
+        tessellator.addVertexWithUV(x, y + height, this.zLevel, (u) * uScale, (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width, y + height, this.zLevel, (u + width) * uScale, (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width, y, this.zLevel, (u + width) * uScale, (v) * vScale);
+        tessellator.addVertexWithUV(x, y, this.zLevel, (u) * uScale, (v) * vScale);
         tessellator.draw();
     }
-    public void drawTexturedModalRect(int x, int y, int u, int v, int width, int height, double uScale, double vScale)
+    public void drawTexturedModalRect(final int x, final int y, final int u, final int v, final int width, final int height, final double uScale, final double vScale)
     {
         final double off = 0.05d;
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x - off,        y + height + off,   zLevel, (u + 0) * uScale,        (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y + height + off,   zLevel, (u + width) * uScale,    (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y - off,            zLevel, (u + width) * uScale,    (v + 0) * vScale);
-        tessellator.addVertexWithUV(x - off,        y - off,            zLevel, (u + 0) * uScale,        (v + 0) * vScale);
+        tessellator.addVertexWithUV(x - off,        y + height + off, this.zLevel, (u) * uScale,        (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y + height + off, this.zLevel, (u + width) * uScale,    (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y - off, this.zLevel, (u + width) * uScale,    (v) * vScale);
+        tessellator.addVertexWithUV(x - off,        y - off, this.zLevel, (u) * uScale,        (v) * vScale);
         tessellator.draw();
     }
-    public void drawTexturedModalRectDouble(double x, double y, double u, double v, double width, double height, double uScale, double vScale)
+    public void drawTexturedModalRectDouble(final double x, final double y, final double u, final double v, final double width, final double height, final double uScale, final double vScale)
     {
         final double off = 0.05d;
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x - off,        y + height + off,   zLevel, (u + 0) * uScale,        (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y + height + off,   zLevel, (u + width) * uScale,    (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y - off,            zLevel, (u + width) * uScale,    (v + 0) * vScale);
-        tessellator.addVertexWithUV(x - off,        y - off,            zLevel, (u + 0) * uScale,        (v + 0) * vScale);
+        tessellator.addVertexWithUV(x - off,        y + height + off, this.zLevel, (u + 0) * uScale,        (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y + height + off, this.zLevel, (u + width) * uScale,    (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y - off, this.zLevel, (u + width) * uScale,    (v + 0) * vScale);
+        tessellator.addVertexWithUV(x - off,        y - off, this.zLevel, (u + 0) * uScale,        (v + 0) * vScale);
         tessellator.draw();
     }
 
-    public void drawTexturedModalRect(int x, int y, int u, int v, int width, int height, double uScale, double vScale, double off)
+    public void drawTexturedModalRect(final int x, final int y, final int u, final int v, final int width, final int height, final double uScale, final double vScale, final double off)
     {
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x - off,        y + height + off,   zLevel, (u + 0) * uScale,        (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y + height + off,   zLevel, (u + width) * uScale,    (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y - off,            zLevel, (u + width) * uScale,    (v + 0) * vScale);
-        tessellator.addVertexWithUV(x - off,        y - off,            zLevel, (u + 0) * uScale,        (v + 0) * vScale);
+        tessellator.addVertexWithUV(x - off,        y + height + off, this.zLevel, (u) * uScale,        (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y + height + off, this.zLevel, (u + width) * uScale,    (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y - off, this.zLevel, (u + width) * uScale,    (v) * vScale);
+        tessellator.addVertexWithUV(x - off,        y - off, this.zLevel, (u) * uScale,        (v) * vScale);
         tessellator.draw();
     }
 
-    public void drawTexturedModalRectDouble(double x, double y, double u, double v, double width, double height, double uScale, double vScale, double off)
+    public void drawTexturedModalRectDouble(final double x, final double y, final double u, final double v, final double width, final double height, final double uScale, final double vScale, final double off)
     {
         final double foon = /*(0.25d * uScale)*/0;
         final double goon = /*(0.25d * vScale)*/0;
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x - off,        y + height + off,   zLevel, (u + 0.5) * uScale,       (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y + height + off,   zLevel, (u + width - 0.5) * uScale,   (v + height) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y - off,            zLevel, (u + width - 0.5) * uScale,    v * vScale);
-        tessellator.addVertexWithUV(x - off,        y - off,            zLevel, (u + 0.5) * uScale,        v * vScale);
+        tessellator.addVertexWithUV(x - off,        y + height + off, this.zLevel, (u + 0.5) * uScale,       (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y + height + off, this.zLevel, (u + width - 0.5) * uScale,   (v + height) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y - off, this.zLevel, (u + width - 0.5) * uScale,    v * vScale);
+        tessellator.addVertexWithUV(x - off,        y - off, this.zLevel, (u + 0.5) * uScale,        v * vScale);
         tessellator.draw();
     }
 
 
-    public void drawTexturedModalRectDouble(double x, double y, double u, double v, double width, double height, double uWidth, double vHeight, double uScale, double vScale)
+    public void drawTexturedModalRectDouble(final double x, final double y, final double u, final double v, final double width, final double height, final double uWidth, final double vHeight, final double uScale, final double vScale)
     {
         final double foon = (0.5f * uScale);
         final double goon = 0.0625f * (16.0f / uWidth);
         final double off = 0.05d;
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x - off,        y + height + off,   zLevel, (u + foon) * uScale,             (v + vHeight - foon) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y + height + off,   zLevel, (u + uWidth - foon) * uScale,    (v + vHeight - foon) * vScale);
-        tessellator.addVertexWithUV(x + width + off,y - off,            zLevel, (u + uWidth - foon) * uScale,    (v + foon) * vScale);
-        tessellator.addVertexWithUV(x - off,        y - off,            zLevel, (u + foon) * uScale,             (v + foon) * vScale);
+        tessellator.addVertexWithUV(x - off,        y + height + off, this.zLevel, (u + foon) * uScale,             (v + vHeight - foon) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y + height + off, this.zLevel, (u + uWidth - foon) * uScale,    (v + vHeight - foon) * vScale);
+        tessellator.addVertexWithUV(x + width + off,y - off, this.zLevel, (u + uWidth - foon) * uScale,    (v + foon) * vScale);
+        tessellator.addVertexWithUV(x - off,        y - off, this.zLevel, (u + foon) * uScale,             (v + foon) * vScale);
         tessellator.draw();
     }
 
-    public void drawTexturedModalRect(double x, double y, int u, int v, int width, int height, int uvWidth, int uvHeight)
+    public void drawTexturedModalRect(final double x, final double y, final int u, final int v, final int width, final int height, final int uvWidth, final int uvHeight)
     {
-        float uScale = 0.00390625F;
-        float vScale = 0.00390625F;
-        Tessellator tessellator = Tessellator.instance;
+        final float uScale = 0.00390625F;
+        final float vScale = 0.00390625F;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x + 0, y + height, zLevel, (u + 0) * uScale, (v + uvHeight) * vScale);
-        tessellator.addVertexWithUV(x + width, y + height, zLevel, (u + uvWidth) * uScale, (v + uvHeight) * vScale);
-        tessellator.addVertexWithUV(x + width, y + 0, zLevel, (u + uvWidth) * uScale, (v + 0) * vScale);
-        tessellator.addVertexWithUV(x + 0, y + 0, zLevel, (u + 0) * uScale, (v + 0) * vScale);
+        tessellator.addVertexWithUV(x + 0, y + height, this.zLevel, (u) * uScale, (v + uvHeight) * vScale);
+        tessellator.addVertexWithUV(x + width, y + height, this.zLevel, (u + uvWidth) * uScale, (v + uvHeight) * vScale);
+        tessellator.addVertexWithUV(x + width, y + 0, this.zLevel, (u + uvWidth) * uScale, (v) * vScale);
+        tessellator.addVertexWithUV(x + 0, y + 0, this.zLevel, (u) * uScale, (v) * vScale);
         tessellator.draw();
     }
     
-    public void drawTexturedModalRect(int x, int y, int u, int v, int width, int height, int uvWidth, float scale)
+    public void drawTexturedModalRect(final int x, final int y, final int u, final int v, final int width, final int height, final int uvWidth, final float scale)
     {
-        float uScale = scale;
-        float vScale = scale;
-        Tessellator tessellator = Tessellator.instance;
+        final float uScale = scale;
+        final float vScale = scale;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x + 0, y + height, zLevel, (u + 0) * uScale, (v + uvWidth) * vScale);
-        tessellator.addVertexWithUV(x + width, y + height, zLevel, (u + uvWidth) * uScale, (v + uvWidth) * vScale);
-        tessellator.addVertexWithUV(x + width, y + 0, zLevel, (u + uvWidth) * uScale, (v + 0) * vScale);
-        tessellator.addVertexWithUV(x + 0, y + 0, zLevel, (u + 0) * uScale, (v + 0) * vScale);
+        tessellator.addVertexWithUV(x, y + height, this.zLevel, (u) * uScale, (v + uvWidth) * vScale);
+        tessellator.addVertexWithUV(x + width, y + height, this.zLevel, (u + uvWidth) * uScale, (v + uvWidth) * vScale);
+        tessellator.addVertexWithUV(x + width, y, this.zLevel, (u + uvWidth) * uScale, (v) * vScale);
+        tessellator.addVertexWithUV(x, y, this.zLevel, (u) * uScale, (v) * vScale);
         tessellator.draw();
     }
-    public void drawTexturedIcon(int x, int y, int width, int height, IconCoordinate coordinate)
+    public void drawTexturedIcon(final int x, final int y, final int width, final int height, final IconCoordinate coordinate)
     {
         coordinate.parentAtlas.bind();
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator tessellator = Tessellator.instance;
         tessellator.startDrawingQuads();
-        tessellator.addVertexWithUV(x + 0,      y + height, zLevel, coordinate.getIconUMin(), coordinate.getIconVMax());
-        tessellator.addVertexWithUV(x + width,  y + height, zLevel, coordinate.getIconUMax(), coordinate.getIconVMax());
-        tessellator.addVertexWithUV(x + width,  y + 0,      zLevel, coordinate.getIconUMax(), coordinate.getIconVMin());
-        tessellator.addVertexWithUV(x + 0,      y + 0,      zLevel, coordinate.getIconUMin(), coordinate.getIconVMin());
+        tessellator.addVertexWithUV(x,      y + height, this.zLevel, coordinate.getIconUMin(), coordinate.getIconVMax());
+        tessellator.addVertexWithUV(x + width,  y + height, this.zLevel, coordinate.getIconUMax(), coordinate.getIconVMax());
+        tessellator.addVertexWithUV(x + width, y, this.zLevel, coordinate.getIconUMax(), coordinate.getIconVMin());
+        tessellator.addVertexWithUV(x, y, this.zLevel, coordinate.getIconUMin(), coordinate.getIconVMin());
         tessellator.draw();
     }
 
-    public void drawGuiTexture(TextureManager re, int x, int y, int width, int height, String texture) {
-        Texture tex = re.loadTexture(texture);
+    public void drawGuiTexture(final TextureManager re, final int x, final int y, final int width, final int height, final String texture) {
+        final Texture tex = re.loadTexture(texture);
         tex.bind();
 
-        Tessellator t = Tessellator.instance;
+        final Tessellator t = Tessellator.instance;
         if (tex.hasMeta("gui")) {
-            GuiTextureProperties properties = Objects.requireNonNull(tex.getMeta("gui", GuiTextureProperties.class));
+            final GuiTextureProperties properties = Objects.requireNonNull(tex.getMeta("gui", GuiTextureProperties.class));
             switch (properties.type) {
                 case GuiTextureProperties.TYPE_STRETCH: {
                     t.startDrawingQuads();
-                    t.addVertexWithUV(x, y + height, zLevel, 0, 1);
-                    t.addVertexWithUV(x + width, y + height, zLevel, 1, 1);
-                    t.addVertexWithUV(x + width, y, zLevel, 1, 0);
-                    t.addVertexWithUV(x, y, zLevel, 0, 0);
+                    t.addVertexWithUV(x, y + height, this.zLevel, 0, 1);
+                    t.addVertexWithUV(x + width, y + height, this.zLevel, 1, 1);
+                    t.addVertexWithUV(x + width, y, this.zLevel, 1, 0);
+                    t.addVertexWithUV(x, y, this.zLevel, 0, 0);
                     t.draw();
                     break;
                 }
                 case GuiTextureProperties.TYPE_TILE: {
-                    double uScale = 1d/ properties.width;
-                    double vScale = 1d/ properties.height;
+                    final double uScale = 1d/ properties.width;
+                    final double vScale = 1d/ properties.height;
                     t.startDrawingQuads();
-                    t.addVertexWithUV(x        , y + height, zLevel, 0,              height * vScale);
-                    t.addVertexWithUV(x + width, y + height, zLevel, width * uScale, height * vScale);
-                    t.addVertexWithUV(x + width, y         , zLevel, width * uScale, 0);
-                    t.addVertexWithUV(x        , y         , zLevel, 0,              0);
+                    t.addVertexWithUV(x        , y + height, this.zLevel, 0,              height * vScale);
+                    t.addVertexWithUV(x + width, y + height, this.zLevel, width * uScale, height * vScale);
+                    t.addVertexWithUV(x + width, y         , this.zLevel, width * uScale, 0);
+                    t.addVertexWithUV(x        , y         , this.zLevel, 0,              0);
                     t.draw();
                     break;
                 }
                 case GuiTextureProperties.TYPE_NINE_SLICE: {
-                    double uScale = 1d / properties.width;
-                    double vScale = 1d / properties.height;
+                    final double uScale = 1d / properties.width;
+                    final double vScale = 1d / properties.height;
 
-                    int innerWidth = properties.width - (properties.border.left + properties.border.right);
-                    int innerHeight = properties.height - (properties.border.top + properties.border.bottom);
-                    int innerLeft = properties.border.left;
-                    int innerTop = properties.border.top;
-                    int innerRight = properties.width - properties.border.right;
-                    int innerBottom = properties.height - properties.border.bottom;
+                    final int innerWidth = properties.width - (properties.border.left + properties.border.right);
+                    final int innerHeight = properties.height - (properties.border.top + properties.border.bottom);
+                    final int innerLeft = properties.border.left;
+                    final int innerTop = properties.border.top;
+                    final int innerRight = properties.width - properties.border.right;
+                    final int innerBottom = properties.height - properties.border.bottom;
 
-                    int leftHeight = height - (properties.border.top + properties.border.bottom);
-                    int repeatsY = leftHeight / innerHeight;
-                    int remainderY = leftHeight % innerHeight;
+                    final int leftHeight = height - (properties.border.top + properties.border.bottom);
+                    final int repeatsY = leftHeight / innerHeight;
+                    final int remainderY = leftHeight % innerHeight;
 
-                    int topWidth = width - (properties.border.left + properties.border.right);
-                    int repeatsX = topWidth / innerWidth;
-                    int remainderX = topWidth % innerWidth;
+                    final int topWidth = width - (properties.border.left + properties.border.right);
+                    final int repeatsX = topWidth / innerWidth;
+                    final int remainderX = topWidth % innerWidth;
 
                     { // Inner
                         if (properties.stretchInner) { // Stretch Inner // TODO implement
@@ -535,41 +516,41 @@ public class Gui
             }
         } else {
             t.startDrawingQuads();
-            t.addVertexWithUV(x        , y + height, zLevel, 0, 1);
-            t.addVertexWithUV(x + width, y + height, zLevel, 1, 1);
-            t.addVertexWithUV(x + width, y         , zLevel, 1, 0);
-            t.addVertexWithUV(x        , y         , zLevel, 0, 0);
+            t.addVertexWithUV(x        , y + height, this.zLevel, 0, 1);
+            t.addVertexWithUV(x + width, y + height, this.zLevel, 1, 1);
+            t.addVertexWithUV(x + width, y         , this.zLevel, 1, 0);
+            t.addVertexWithUV(x        , y         , this.zLevel, 0, 0);
             t.draw();
         }
     }
 
-    public void drawGuiIcon(int x, int y, int width, int height, IconCoordinate coordinate) {
+    public void drawGuiIcon(final int x, final int y, final int width, final int height, final IconCoordinate coordinate) {
         drawGuiIconDouble(x, y, width, height, coordinate);
     }
-    public void drawGuiIconDouble(double x, double y, double width, double height, IconCoordinate coordinate) {
+    public void drawGuiIconDouble(final double x, final double y, final double width, final double height, final IconCoordinate coordinate) {
         coordinate.parentAtlas.bind();
-        Tessellator t = Tessellator.instance;
+        final Tessellator t = Tessellator.instance;
         if (coordinate.hasMeta("gui")) {
-            GuiTextureProperties properties = Objects.requireNonNull(coordinate.getMeta("gui", GuiTextureProperties.class));
+            final GuiTextureProperties properties = Objects.requireNonNull(coordinate.getMeta("gui", GuiTextureProperties.class));
             switch (properties.type) {
                 case GuiTextureProperties.TYPE_STRETCH: {
                     t.startDrawingQuads();
-                    t.addVertexWithUV(x,            y + height, zLevel, coordinate.getIconUMin(), coordinate.getIconVMax());
-                    t.addVertexWithUV(x + width,    y + height, zLevel, coordinate.getIconUMax(), coordinate.getIconVMax());
-                    t.addVertexWithUV(x + width,    y,          zLevel, coordinate.getIconUMax(), coordinate.getIconVMin());
-                    t.addVertexWithUV(x,            y,          zLevel, coordinate.getIconUMin(), coordinate.getIconVMin());
+                    t.addVertexWithUV(x,            y + height, this.zLevel, coordinate.getIconUMin(), coordinate.getIconVMax());
+                    t.addVertexWithUV(x + width,    y + height, this.zLevel, coordinate.getIconUMax(), coordinate.getIconVMax());
+                    t.addVertexWithUV(x + width,    y, this.zLevel, coordinate.getIconUMax(), coordinate.getIconVMin());
+                    t.addVertexWithUV(x,            y, this.zLevel, coordinate.getIconUMin(), coordinate.getIconVMin());
                     t.draw();
                     break;
                 }
                 case GuiTextureProperties.TYPE_TILE: {
-                    int repeatsY = MathHelper.floor(height / properties.height);
-                    double remainderY = height % properties.height;
+                    final int repeatsY = MathHelper.floor(height / properties.height);
+                    final double remainderY = height % properties.height;
 
-                    int repeatsX = MathHelper.floor(width / properties.width);
-                    double remainderX = width % properties.width;
+                    final int repeatsX = MathHelper.floor(width / properties.width);
+                    final double remainderX = width % properties.width;
 
-                    double uScale = (double) coordinate.width / properties.width;
-                    double vScale = (double) coordinate.height / properties.height;
+                    final double uScale = (double) coordinate.width / properties.width;
+                    final double vScale = (double) coordinate.height / properties.height;
 
                     for (int i = 0; i < repeatsX; i++) {
                         for (int j = 0; j < repeatsY; j++) {
@@ -610,23 +591,23 @@ public class Gui
                     break;
                 }
                 case GuiTextureProperties.TYPE_NINE_SLICE: {
-                    int innerWidth = properties.width - (properties.border.left + properties.border.right);
-                    int innerHeight = properties.height - (properties.border.top + properties.border.bottom);
-                    int innerLeft = properties.border.left;
-                    int innerTop = properties.border.top;
-                    int innerRight = properties.width - properties.border.right;
-                    int innerBottom = properties.height - properties.border.bottom;
+                    final int innerWidth = properties.width - (properties.border.left + properties.border.right);
+                    final int innerHeight = properties.height - (properties.border.top + properties.border.bottom);
+                    final int innerLeft = properties.border.left;
+                    final int innerTop = properties.border.top;
+                    final int innerRight = properties.width - properties.border.right;
+                    final int innerBottom = properties.height - properties.border.bottom;
 
-                    double uScale = (double) coordinate.width / properties.width;
-                    double vScale = (double) coordinate.height / properties.height;
+                    final double uScale = (double) coordinate.width / properties.width;
+                    final double vScale = (double) coordinate.height / properties.height;
 
-                    double leftHeight = height - (properties.border.top + properties.border.bottom);
-                    int repeatsY = MathHelper.floor(leftHeight / innerHeight);
-                    double remainderY = leftHeight % innerHeight;
+                    final double leftHeight = height - (properties.border.top + properties.border.bottom);
+                    final int repeatsY = MathHelper.floor(leftHeight / innerHeight);
+                    final double remainderY = leftHeight % innerHeight;
 
-                    double topWidth = width - (properties.border.left + properties.border.right);
-                    int repeatsX = MathHelper.floor(topWidth / innerWidth);
-                    double remainderX = topWidth % innerWidth;
+                    final double topWidth = width - (properties.border.left + properties.border.right);
+                    final int repeatsX = MathHelper.floor(topWidth / innerWidth);
+                    final double remainderX = topWidth % innerWidth;
 
 
                     { // Inner
@@ -768,41 +749,41 @@ public class Gui
         }
     }
 
-    public void drawIconTexture(int x0, int y0, int x1, int y1, int u0, int v0, int u1, int v1, IconCoordinate coordinate) {
+    public void drawIconTexture(final int x0, final int y0, final int x1, final int y1, final int u0, final int v0, final int u1, final int v1, final IconCoordinate coordinate) {
         coordinate.parentAtlas.bind();
 
-        double realU0 = coordinate.getSubIconU(u0 /((double)coordinate.width));
-        double realU1 = coordinate.getSubIconU(u1 /((double)coordinate.width));
-        double realV0 = coordinate.getSubIconV(v0 /((double)coordinate.height));
-        double realV1 = coordinate.getSubIconV(v1 /((double)coordinate.height));
+        final double realU0 = coordinate.getSubIconU(u0 /((double)coordinate.width));
+        final double realU1 = coordinate.getSubIconU(u1 /((double)coordinate.width));
+        final double realV0 = coordinate.getSubIconV(v0 /((double)coordinate.height));
+        final double realV1 = coordinate.getSubIconV(v1 /((double)coordinate.height));
 
 //        System.out.printf("%s, %s, %s, %s\n", realU0, realU1, realV0, realV1);
 
-        Tessellator t = Tessellator.instance;
+        final Tessellator t = Tessellator.instance;
         t.startDrawingQuads();
-        t.addVertexWithUV(x0, y1, zLevel, realU0, realV1);
-        t.addVertexWithUV(x1, y1, zLevel, realU1, realV1);
-        t.addVertexWithUV(x1, y0, zLevel, realU1, realV0);
-        t.addVertexWithUV(x0, y0, zLevel, realU0, realV0);
+        t.addVertexWithUV(x0, y1, this.zLevel, realU0, realV1);
+        t.addVertexWithUV(x1, y1, this.zLevel, realU1, realV1);
+        t.addVertexWithUV(x1, y0, this.zLevel, realU1, realV0);
+        t.addVertexWithUV(x0, y0, this.zLevel, realU0, realV0);
         t.draw();
     }
 
-    public void drawIconTextureDouble(double x0, double y0, double x1, double y1, double u0, double v0, double u1, double v1, IconCoordinate coordinate) {
+    public void drawIconTextureDouble(final double x0, final double y0, final double x1, final double y1, final double u0, final double v0, final double u1, final double v1, final IconCoordinate coordinate) {
         coordinate.parentAtlas.bind();
 
-        double realU0 = coordinate.getSubIconU(u0 /((double)coordinate.width));
-        double realU1 = coordinate.getSubIconU(u1 /((double)coordinate.width));
-        double realV0 = coordinate.getSubIconV(v0 /((double)coordinate.height));
-        double realV1 = coordinate.getSubIconV(v1 /((double)coordinate.height));
+        final double realU0 = coordinate.getSubIconU(u0 /((double)coordinate.width));
+        final double realU1 = coordinate.getSubIconU(u1 /((double)coordinate.width));
+        final double realV0 = coordinate.getSubIconV(v0 /((double)coordinate.height));
+        final double realV1 = coordinate.getSubIconV(v1 /((double)coordinate.height));
 
 //        System.out.printf("%s, %s, %s, %s\n", realU0, realU1, realV0, realV1);
 
-        Tessellator t = Tessellator.instance;
+        final Tessellator t = Tessellator.instance;
         t.startDrawingQuads();
-        t.addVertexWithUV(x0, y1, zLevel, realU0, realV1);
-        t.addVertexWithUV(x1, y1, zLevel, realU1, realV1);
-        t.addVertexWithUV(x1, y0, zLevel, realU1, realV0);
-        t.addVertexWithUV(x0, y0, zLevel, realU0, realV0);
+        t.addVertexWithUV(x0, y1, this.zLevel, realU0, realV1);
+        t.addVertexWithUV(x1, y1, this.zLevel, realU1, realV1);
+        t.addVertexWithUV(x1, y0, this.zLevel, realU1, realV0);
+        t.addVertexWithUV(x0, y0, this.zLevel, realU0, realV0);
         t.draw();
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java b/game/client/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
index b23d0f8b8..f0433812c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/HeldItemTooltipElement.java
@@ -4,6 +4,8 @@ import static org.lwjgl.opengl.GL11.*;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.option.Option;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.util.helper.Time;
@@ -126,7 +128,7 @@ public class HeldItemTooltipElement extends Gui {
 			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 		}
 
-		mc.font.drawStringWithShadow(string, x - (mc.font.getStringWidth(string)) / 2, y, rgb);
+		FontHelper.renderCentered(Tessellator.instance, this.string, x, y).setShadow().setColor(rgb).call(mc.font);
 
 		glDisable(GL_BLEND);
 		glEnable(GL_ALPHA_TEST);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/IntegerSliderElement.java b/game/client/src/main/java/net/minecraft/client/gui/IntegerSliderElement.java
index cfc3a7f29..efeda51d5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/IntegerSliderElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/IntegerSliderElement.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.gui;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import org.lwjgl.opengl.GL11;
@@ -12,6 +11,7 @@ public class IntegerSliderElement extends ButtonElement {
 
 	public int sliderValue;
 	public boolean dragging;
+	public boolean renderText = true;
 	private OptionToggleable<?> option;
 
 	public IconCoordinate backgroundTexture;
@@ -67,7 +67,6 @@ public class IntegerSliderElement extends ButtonElement {
 	public void drawButton(Minecraft mc, int mouseX, int mouseY) {
 		if (!visible) return;
 
-		Font font = mc.font;
 		boolean mouseOver = mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height;
 		int state = getButtonState(mouseOver);
 
@@ -108,8 +107,10 @@ public class IntegerSliderElement extends ButtonElement {
 				textColor = 0xFFFFA0;
 				break;
 		}
-		drawStringCentered(font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
 
+		if (this.renderText) {
+			drawStringCenteredShadow(mc.font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
+		}
 	}
 
 	@Override
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 8176b3eb0..76015a8f2 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
@@ -7,15 +7,14 @@ import java.util.List;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.input.controller.ControllerInput;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.window.CursorShape;
-import net.minecraft.client.render.window.GameWindowGLFW;
 import net.minecraft.client.util.debug.DebugRender;
 import net.minecraft.client.input.InputType;
 
 import net.minecraft.core.sound.SoundCategory;
-import org.lwjgl.glfw.GLFW;
+import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -26,16 +25,17 @@ public abstract class Screen extends Gui {
     public int height;
     public List<ButtonElement> buttons;
     public boolean passEvents;
-    public Font font;
+    public FontRenderer fontRenderer;
     protected ButtonElement clickedButton;
     final Screen parentScreen;
     private CursorShape desiredCursor = CursorShape.ARROW;
 
-    public Screen(Screen parent) {
-        buttons = new ArrayList<>();
-        passEvents = false;
-        clickedButton = null;
-        parentScreen = parent;
+    public Screen(@Nullable final Screen parent) {
+        super();
+        this.buttons = new ArrayList<>();
+        this.passEvents = false;
+        this.clickedButton = null;
+        this.parentScreen = parent;
     }
 
     public Screen() {
@@ -108,7 +108,7 @@ public abstract class Screen extends Gui {
 
     public void opened(Minecraft mc, int width, int height) {
         this.mc = mc;
-        font = mc.font;
+        fontRenderer = mc.font;
         this.width = width;
         this.height = height;
         buttons.clear();
@@ -241,6 +241,6 @@ public abstract class Screen extends Gui {
     }
 
     public void updateFont() {
-        this.font = mc.font;
+        this.fontRenderer = this.mc.font;
     }
 }
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 ae8734f2e..acb97bfb7 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
@@ -36,10 +36,10 @@ public class ScreenAddServer extends Screen
         buttons.clear();
         buttons.add(buttonSave = new ButtonElement(0, width / 2 - 100, height / 4 + 96 + 12, stringtranslate.translateKey("gui.add_server.button.save")));
         buttons.add(buttonCancel = new ButtonElement(1, width / 2 - 100, height / 4 + 120 + 12, stringtranslate.translateKey("gui.add_server.button.cancel")));
-        serverNameTextField = new TextFieldElement(this, font, width / 2 - 100, (height / 4 - 10) + 18, 200, 20, "", "");
+        serverNameTextField = new TextFieldElement(this, fontRenderer, width / 2 - 100, (height / 4 - 10) + 18, 200, 20, "", "");
         serverNameTextField.isFocused = true;
         serverNameTextField.setMaxStringLength(32);
-        ipTextField = new TextFieldElement(this, font, width / 2 - 100, (height / 4 - 10) + 50 + 18, 200, 20, "", "");
+        ipTextField = new TextFieldElement(this, fontRenderer, width / 2 - 100, (height / 4 - 10) + 50 + 18, 200, 20, "", "");
         ipTextField.setMaxStringLength(128);
         buttons.add(buttonShowIp = new ButtonElement(2, width / 2 - 100, (height / 4 - 10) + 50 + 18 + 20 + 4, 200, 20, getShowIpLabel()));
         buttonSave.enabled = false;
@@ -135,9 +135,9 @@ public class ScreenAddServer extends Screen
     {
         I18n stringtranslate = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, stringtranslate.translateKey("gui.add_server.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
-        drawString(font, stringtranslate.translateKey("gui.add_server.label.server_name"), serverNameTextField.xPosition, serverNameTextField.yPosition - 14, 0xa0a0a0);
-        drawString(font, stringtranslate.translateKey("gui.add_server.label.ip_address"), ipTextField.xPosition, ipTextField.yPosition - 14, 0xa0a0a0);
+        drawStringCenteredShadow(fontRenderer, stringtranslate.translateKey("gui.add_server.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
+        drawStringShadow(fontRenderer, stringtranslate.translateKey("gui.add_server.label.server_name"), serverNameTextField.xPosition, serverNameTextField.yPosition - 14, 0xa0a0a0);
+        drawStringShadow(fontRenderer, stringtranslate.translateKey("gui.add_server.label.ip_address"), ipTextField.xPosition, ipTextField.yPosition - 14, 0xa0a0a0);
         ipTextField.drawTextBox();
         ipTextField.updateCursor(mc, mx, my);
         serverNameTextField.drawTextBox();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenBadJavaArch.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenBadJavaArch.java
index 3449f27d0..f00bb7674 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenBadJavaArch.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenBadJavaArch.java
@@ -2,6 +2,7 @@ package net.minecraft.client.gui;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
 import org.slf4j.Logger;
 
 import java.awt.*;
@@ -22,7 +23,7 @@ public class ScreenBadJavaArch extends Screen
         buttons.clear();
         String downloadString = i.translateKey("gui.bad_java_arch.button.download");
         buttons.add(new ButtonElement(0, width / 2 - 100, height / 4 + 120 + 12, i.translateKey("gui.bad_java_arch.button.continue")));
-        buttons.add(new ClickableLabelElement(1, width / 2 - 170 - font.getStringWidth(downloadString) / 2, (height / 4 - 60) + 60 + 64, downloadString, 0x7C99EA));
+        buttons.add(new ClickableLabelElement(1, width / 2 - 170 - MathHelper.ceil(fontRenderer.stringWidthDouble(downloadString) / 2), (height / 4 - 60) + 60 + 64, downloadString, 0x7C99EA));
     }
 
     @Override
@@ -58,11 +59,11 @@ public class ScreenBadJavaArch extends Screen
     {
         I18n i = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, i.translateKey("gui.bad_java_arch.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
-        drawString(font, i.translateKey("gui.bad_java_arch.label.body.1"), width / 2 - 170, (height / 4 - 60) + 60 + 0, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.bad_java_arch.label.body.2"), width / 2 - 170, (height / 4 - 60) + 60 + 18, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.bad_java_arch.label.body.3"), width / 2 - 170, (height / 4 - 60) + 60 + 27, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.bad_java_arch.label.body.4"), width / 2 - 170, (height / 4 - 60) + 60 + 45, 0xa0a0a0);
+        drawStringCenteredShadow(fontRenderer, i.translateKey("gui.bad_java_arch.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
+        drawStringShadow(fontRenderer, i.translateKey("gui.bad_java_arch.label.body.1"), width / 2 - 170, (height / 4 - 60) + 60 + 0, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.bad_java_arch.label.body.2"), width / 2 - 170, (height / 4 - 60) + 60 + 18, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.bad_java_arch.label.body.3"), width / 2 - 170, (height / 4 - 60) + 60 + 27, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.bad_java_arch.label.body.4"), width / 2 - 170, (height / 4 - 60) + 60 + 45, 0xa0a0a0);
         super.render(mx, my, partialTick);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConflictWarning.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConflictWarning.java
index ddf85e1a4..e3da98477 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConflictWarning.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConflictWarning.java
@@ -34,11 +34,11 @@ public class ScreenConflictWarning extends Screen
     {
         I18n i = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, i.translateKey("gui.conflict_warning.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
-        drawString(font, i.translateKey("gui.conflict_warning.label.body.1"), width / 2 - 140, (height / 4 - 60) + 60 + 0, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.conflict_warning.label.body.2"), width / 2 - 140, (height / 4 - 60) + 60 + 18, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.conflict_warning.label.body.3"), width / 2 - 140, (height / 4 - 60) + 60 + 27, 0xa0a0a0);
-        drawString(font, i.translateKey("gui.conflict_warning.label.body.4"), width / 2 - 140, (height / 4 - 60) + 60 + 45, 0xa0a0a0);
+        drawStringCenteredShadow(fontRenderer, i.translateKey("gui.conflict_warning.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
+        drawStringShadow(fontRenderer, i.translateKey("gui.conflict_warning.label.body.1"), width / 2 - 140, (height / 4 - 60) + 60 + 0, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.conflict_warning.label.body.2"), width / 2 - 140, (height / 4 - 60) + 60 + 18, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.conflict_warning.label.body.3"), width / 2 - 140, (height / 4 - 60) + 60 + 27, 0xa0a0a0);
+        drawStringShadow(fontRenderer, i.translateKey("gui.conflict_warning.label.body.4"), width / 2 - 140, (height / 4 - 60) + 60 + 45, 0xa0a0a0);
         super.render(mx, my, partialTick);
     }
 }
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 e5a2070b3..afa150337 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
@@ -56,8 +56,8 @@ public class ScreenConnectFailed extends Screen
 	public void render(int mx, int my, float partialTick)
     {
         renderBackground();
-        drawStringCentered(font, errorMessage, width / 2, height / 2 - 50, 0xffffff);
-        drawStringCentered(font, errorDetail, width / 2, height / 2 - 10, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, errorMessage, width / 2, height / 2 - 50, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, errorDetail, width / 2, height / 2 - 10, 0xffffff);
         super.render(mx, my, partialTick);
     }
 
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 307ef8273..8bb58bb8b 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
@@ -28,7 +28,7 @@ public class ScreenConnectToIp extends Screen
         buttons.add(new ButtonElement(1, width / 2 - 100, height / 4 + 120 + 12, stringtranslate.translateKey("gui.connect_to_ip.button.cancel")));
         String s = mc.gameSettings.lastServer.value.replaceAll("_", ":");
         buttons.get(0).enabled = s.length() > 0;
-        textField = new TextFieldElement(this, font, width / 2 - 100, (height / 4 - 10) + 50 + 18, 200, 20, s, "");
+        textField = new TextFieldElement(this, fontRenderer, width / 2 - 100, (height / 4 - 10) + 50 + 18, 200, 20, s, "");
         textField.isFocused = true;
         textField.setMaxStringLength(128);
     }
@@ -84,8 +84,8 @@ public class ScreenConnectToIp extends Screen
     {
         I18n i18n = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, i18n.translateKey("gui.connect_to_ip.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
-        drawString(font, i18n.translateKey("gui.connect_to_ip.label.enter_ip"), width / 2 - 140, (height / 4 - 60) + 60 + 36, 0xa0a0a0);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey("gui.connect_to_ip.label.title"), width / 2, (height / 4 - 60) + 20, 0xffffff);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.connect_to_ip.label.enter_ip"), width / 2 - 140, (height / 4 - 60) + 60 + 36, 0xa0a0a0);
         textField.drawTextBox();
         textField.updateCursor(mc, mx, my);
         super.render(mx, my, partialTick);
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 f2b6cf798..9d28afb55 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
@@ -107,12 +107,12 @@ public class ScreenConnecting extends Screen
         I18n stringtranslate = I18n.getInstance();
         if(clientHandler == null)
         {
-            drawStringCentered(font, stringtranslate.translateKey("gui.connecting.label.connecting"), width / 2, height / 2 - 50, 0xffffff);
-            drawStringCentered(font, "", width / 2, height / 2 - 10, 0xffffff);
+            drawStringCenteredShadow(fontRenderer, stringtranslate.translateKey("gui.connecting.label.connecting"), width / 2, height / 2 - 50, 0xffffff);
+            drawStringCenteredShadow(fontRenderer, "", width / 2, height / 2 - 10, 0xffffff);
         } else
         {
-            drawStringCentered(font, stringtranslate.translateKey("gui.connecting.label.logging_in"), width / 2, height / 2 - 50, 0xffffff);
-            drawStringCentered(font, clientHandler.message, width / 2, height / 2 - 10, 0xffffff);
+            drawStringCenteredShadow(fontRenderer, stringtranslate.translateKey("gui.connecting.label.logging_in"), width / 2, height / 2 - 50, 0xffffff);
+            drawStringCenteredShadow(fontRenderer, clientHandler.message, width / 2, height / 2 - 10, 0xffffff);
         }
         super.render(mx, my, partialTick);
     }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java
index e9574cef9..f39fb603f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenConsole.java
@@ -7,15 +7,17 @@ import net.minecraft.client.console.LogMessageReceiver;
 import net.minecraft.client.console.syntax.RendererFactory;
 import net.minecraft.client.gui.text.ITextField;
 import net.minecraft.client.gui.text.TextFieldEditor;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontMonospace;
 import net.minecraft.client.console.shell.RuntimeExecutor;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.FontRendererDefault;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.window.CursorShape;
-import net.minecraft.client.render.window.GameWindowGLFW;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.lwjgl.glfw.GLFW;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -36,7 +38,7 @@ public class ScreenConsole extends Screen {
 
         private final @NotNull Map<LogMessage.@NotNull Level, @NotNull TextFormatting> preludes = new HashMap<>();
 
-        private @Nullable Font font = null;
+        private @Nullable FontRenderer fontRenderer = null;
 
         private int width = 0;
         private int scroll = 0;
@@ -51,7 +53,8 @@ public class ScreenConsole extends Screen {
 
         public void init(final @NotNull Minecraft mc, final int width) {
             this.width = width;
-            this.font = new Font(mc, mc.gameSettings, mc.textureManager, true);
+            this.fontRenderer = new FontRendererDefault(new FontMonospace(mc.textureManager));
+            this.fontRenderer.init(mc.texturePackList);
 
             initWorkedLines();
             final @NotNull List<@NotNull String> workedLine = new ArrayList<>();
@@ -73,8 +76,8 @@ public class ScreenConsole extends Screen {
             final int lines = Math.min(heightLines, WORKED_LINES.size() - this.scroll);
             for (int i = lines - 1; i >= 0; i--) {
                 final @NotNull String line = WORKED_LINES.get((WORKED_LINES.size() - 1) - (i + this.scroll));
-                if (this.font != null) {
-                    this.font.drawString(line, x, y + getHeight(numLines) - LINE_HEIGHT - LINE_HEIGHT * i, 0xFF_CF_CF_CF);
+                if (this.fontRenderer != null) {
+                    FontHelper.render(Tessellator.instance, line, x, y + getHeight(numLines) - LINE_HEIGHT - LINE_HEIGHT * i).setColor(0xFF_CF_CF_CF).call(this.fontRenderer);
                 }
             }
             renderScrollIndicator(x, y, numLines);
@@ -136,7 +139,7 @@ public class ScreenConsole extends Screen {
         }
 
         private void formatString(final @NotNull LogMessage message, final @NotNull List<@NotNull String> out) {
-            if (this.font == null) {
+            if (this.fontRenderer == null) {
                 return;
             }
 
@@ -161,9 +164,9 @@ public class ScreenConsole extends Screen {
                         if (newFormat != null) {
                             nextFormat = newFormat;
                         }
-                        lineWidth -= this.font.getCharWidth(c) + this.font.getCharWidth(trimmedLine.charAt(i + 1));
+                        lineWidth -= this.fontRenderer.charWidth(c) + this.fontRenderer.charWidth(trimmedLine.charAt(i + 1));
                     }
-                    final int cWidth = this.font.getCharWidth(c);
+                    final int cWidth = this.fontRenderer.charWidth(c);
                     if (lineWidth + cWidth >= this.width) {
                         out.add(currentFormat.toString() + sb);
                         sb = new StringBuilder();
@@ -182,7 +185,7 @@ public class ScreenConsole extends Screen {
         private static final @NotNull List<@NotNull String> HISTORY = new ArrayList<>();
         private static final @Nullable RuntimeExecutor EXECUTOR = new RuntimeExecutor();
 
-        private @Nullable Font font = null;
+        private @Nullable FontRenderer fontRenderer = null;
 
         private @NotNull String text = "";
         private @NotNull String highlightedText = "";
@@ -198,7 +201,8 @@ public class ScreenConsole extends Screen {
         }
 
         public void init(final @NotNull Minecraft mc) {
-            this.font = new Font(mc, mc.gameSettings, mc.textureManager, true);
+            this.fontRenderer = new FontRendererDefault(new FontMonospace(mc.textureManager));
+            this.fontRenderer.init(mc.texturePackList);
         }
 
         public void tick() {
@@ -206,38 +210,38 @@ public class ScreenConsole extends Screen {
         }
 
         public void render(final int x, final int y) {
-            if (this.font == null) return;
+            if (this.fontRenderer == null) return;
 
             boolean addedStart = false;
             final @NotNull String @NotNull[] splitHighlighted = this.highlightedText.split("\n", -1);
             for (int i = 0; i < splitHighlighted.length; i++) {
-                drawStringNoShadow(this.font, (addedStart ? "  " : "> ") + splitHighlighted[i].replace("\n", ""), x, y + i * LINE_HEIGHT, 0xFF_E0_E0_E0);
+                drawStringNoShadow(this.fontRenderer, (addedStart ? "  " : "> ") + splitHighlighted[i].replace("\n", ""), x, y + i * LINE_HEIGHT, 0xFF_E0_E0_E0);
                 addedStart = true;
             }
 
             final @NotNull String @NotNull [] split = this.text.split("\n", -1);
-            final int offsetWidth = this.font.getStringWidth("  ");
+            final int offsetWidth = MathHelper.ceil(this.fontRenderer.stringWidthDouble("  "));
             final int[] cursorPos = getCursor();
             final int cursorX;
             if (cursorPos[0] == split[cursorPos[1]].length()) {
-                cursorX = this.font.getStringWidth(split[cursorPos[1]]);
+                cursorX = MathHelper.ceil(this.fontRenderer.stringWidthDouble(split[cursorPos[1]]));
             } else {
-                cursorX = this.font.getStringWidth(split[cursorPos[1]].substring(0, cursorPos[0]));
+                cursorX = MathHelper.ceil(this.fontRenderer.stringWidthDouble(split[cursorPos[1]].substring(0, cursorPos[0])));
             }
             if ((cursorCounter / 6) % 2 == 0) {
-                drawStringNoShadow(this.font, "█", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_FF_FF_FF);
+                drawStringNoShadow(this.fontRenderer, "█", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_FF_FF_FF);
                 if (this.editor.getCursor() < this.text.length() && this.text.charAt(this.editor.getCursor()) != '\n') {
-                    drawStringNoShadow(this.font, "" + this.text.charAt(this.editor.getCursor()), x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_00_00_00);
+                    drawStringNoShadow(this.fontRenderer, "" + this.text.charAt(this.editor.getCursor()), x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_00_00_00);
                 }
             } else {
-                drawStringNoShadow(this.font, "_", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_FF_FF_FF);
+                drawStringNoShadow(this.fontRenderer, "_", x + offsetWidth + cursorX, y + cursorPos[1] * LINE_HEIGHT, 0xFF_FF_FF_FF);
             }
         }
 
         public void click(final int mx, final int my) {
-            if (this.font == null) return;
+            if (this.fontRenderer == null) return;
 
-            final int oneChar = this.font.getStringWidth(" ");
+            final int oneChar = MathHelper.ceil(this.fontRenderer.stringWidthDouble(" "));
 
             final int cx = (mx - (oneChar * 2)) / oneChar;
             final int cy = my / LINE_HEIGHT;
@@ -375,7 +379,7 @@ public class ScreenConsole extends Screen {
         }
 
         private int @NotNull[] getCursor() {
-            if (this.font == null) {
+            if (this.fontRenderer == null) {
                 return new int[2];
             }
 
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 49512a6ab..11cc12ce4 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
@@ -9,8 +9,6 @@ import net.minecraft.core.lang.I18n;
 
 import java.util.Arrays;
 
-import java.util.Arrays;
-
 import static org.lwjgl.opengl.GL11.*;
 
 public class ScreenControllerSetup extends Screen {
@@ -84,7 +82,7 @@ public class ScreenControllerSetup extends Screen {
 
             glDisable(GL_DEPTH_TEST);
 
-            font.drawCenteredString("(" + controller.getType().getPrintableName() + ")", width / 2, 40, 0xFFFFFF);
+            drawStringCenteredNoShadow(fontRenderer, "(" + controller.getType().getPrintableName() + ")", width / 2, 40, 0xFFFFFF);
 
             mc.textureManager.loadTexture("/assets/minecraft/textures/gui/controller/layout.png").bind();
 
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 301594ee2..463be32ef 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
@@ -57,10 +57,10 @@ public class ScreenCreateWorld extends Screen {
             i18n.translateKey("gui.create_world.button.create_new_world")));
         buttons.add(new ButtonElement(1, width / 2 - 100, height / 4 + 128 + 12,
             i18n.translateKey("gui.create_world.button.cancel")));
-        textboxWorldName = new TextFieldElement(this, font, width / 2 - 100, 60, 200 - 24, 20,
+        textboxWorldName = new TextFieldElement(this, fontRenderer, width / 2 - 100, 60, 200 - 24, 20,
             "", i18n.translateKey("gui.create_world.label.new_world"));
         textboxWorldName.setMaxStringLength(32);
-        textboxSeed = new TextFieldElement(this, font, width / 2 - 100, 100, 200 - 24, 20, "", Long.toString(seed));
+        textboxSeed = new TextFieldElement(this, fontRenderer, width / 2 - 100, 100, 200 - 24, 20, "", Long.toString(seed));
         buttons.add(gamemodeButton = new ButtonElement(2, width / 2 - 100, 100 + 20 + 4, 98, 20, ""));
         buttons.add(cheatsButton = new ButtonElement(3, width / 2 - 100 + 102, 100 + 20 + 4, 98, 20, ""));
         buttons.add(worldTypeButton = new ButtonElement(4, width / 2 - 100, 100 + 20 + 20 + 4 + 4, ""));
@@ -212,9 +212,9 @@ public class ScreenCreateWorld extends Screen {
     public void render(int mx, int my, float partialTick) {
         I18n stringtranslate = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, stringtranslate.translateKey("gui.create_world.label.title"), width / 2, 20, 0xffffff);
-        drawString(font, stringtranslate.translateKey("gui.create_world.label.world_name"), width / 2 - 100, 47, 0xa0a0a0);
-        drawString(font, stringtranslate.translateKey("gui.create_world.label.seed"), width / 2 - 100, 88, 0xa0a0a0);
+        drawStringCenteredShadow(fontRenderer, stringtranslate.translateKey("gui.create_world.label.title"), width / 2, 20, 0xffffff);
+        drawStringShadow(fontRenderer, stringtranslate.translateKey("gui.create_world.label.world_name"), width / 2 - 100, 47, 0xa0a0a0);
+        drawStringShadow(fontRenderer, stringtranslate.translateKey("gui.create_world.label.seed"), width / 2 - 100, 88, 0xa0a0a0);
         textboxWorldName.drawTextBox();
         textboxWorldName.updateCursor(mc, mx, my);
         textboxSeed.drawTextBox();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenCredits.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenCredits.java
index 953bd40f0..650fe998f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenCredits.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenCredits.java
@@ -6,6 +6,7 @@ import net.minecraft.client.render.Scissor;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -120,7 +121,7 @@ public class ScreenCredits extends Screen {
 
         super.render(mx, my, partialTick);
 
-        font.drawCenteredString(I18n.getInstance().translateKey("gui.credits.label.title"), width / 2, 5, 0xFFFFFF);
+        drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey("gui.credits.label.title"), width / 2, 5, 0xFFFFFF);
 
         Scissor.enable(0, top, width, bottom - top);
         drawContent();
@@ -138,15 +139,15 @@ public class ScreenCredits extends Screen {
             String line = lines.get(i);
             if (line.startsWith("*")) {
                 line = TextFormatting.BOLD + line.substring(1);
-                int lineWidth = font.getStringWidth(line) + line.length();
-                font.drawString(line, width / 2 - lineWidth / 2, 100 + i * 12 - (int)scrollAmount, 0xFFFFFF);
+                int lineWidth = MathHelper.ceil(fontRenderer.stringWidthDouble(line)) + line.length();
+                drawStringNoShadow(this.fontRenderer, line, width / 2 - lineWidth / 2, 100 + i * 12 - (int)scrollAmount, 0xFFFFFF);
             } else if (line.startsWith("!")) {
                 int rgb = Color.HSBtoRGB(hue / 360f, 1.0f, 1.0f);
                 line = TextFormatting.BOLD + line.substring(1);
-                int lineWidth = font.getStringWidth(line) + line.length();
-                font.drawString(line, width / 2 - lineWidth / 2, 100 + i * 12 - (int)scrollAmount, rgb);
+                int lineWidth = MathHelper.ceil(fontRenderer.stringWidthDouble(line)) + line.length();
+                drawStringNoShadow(this.fontRenderer, line, width / 2 - lineWidth / 2, 100 + i * 12 - (int)scrollAmount, rgb);
             } else {
-                font.drawString(line, width / 2 - font.getStringWidth(line) / 2, 100 + i * 12 - (int) scrollAmount, 0x7F7F7F);
+                drawStringNoShadow(this.fontRenderer, line, MathHelper.ceil((width - fontRenderer.stringWidthDouble(line)) / 2), 100 + i * 12 - (int) scrollAmount, 0x7F7F7F);
             }
         }
     }
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 c6ff2bb3f..d776d2bb8 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
@@ -49,7 +49,7 @@ public class ScreenDownloadTerrain extends Screen
     {
         renderTexturedBackground();
         I18n i18n = I18n.getInstance();
-        drawStringCentered(font, i18n.translateKey("gui.downloading_terrain.label.title"), width / 2, height / 2 - 50, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey("gui.downloading_terrain.label.title"), width / 2, height / 2 - 50, 0xffffff);
         super.render(mx, my, partialTick);
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java
new file mode 100644
index 000000000..9809e3626
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java
@@ -0,0 +1,94 @@
+package net.minecraft.client.gui;
+
+import net.minecraft.client.render.font.Alignment;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.net.ChatEmotes;
+import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.util.Map;
+
+public class ScreenFontTest extends Screen{
+    public double scroll = 0;
+    public ScreenFontTest(final @Nullable Screen parent) {
+        super(parent);
+    }
+    @Override
+    public void render(final int mx, final int my, final float partialTick) {
+        renderTexturedBackground();
+        super.render(mx, my, partialTick);
+
+        scroll += Mouse.getDWheel() * fontRenderer.fontHeight()/2;
+
+//        drawStringCenteredNoShadow(this.mc.font, "§l§oBetter than Adventure!", this.width /2, this.height /2 - 30, 0x22ffffff);
+//        this.fontRenderer.renderCentered(Tessellator.instance,  "§l§oBetter than Adventure!", this.width /2, this.height /2 - 20, 0, false, 0xffffffL, null, null, null);
+
+//        FontHelper.renderWidthConstrained(Tessellator.instance,
+//            "§bLorem ipsum dolor sit amet, §+§3consectetur adipiscing elit, sed do eiusmod tempor incididunt §+§1ut labore et §+§rdolore magna aliqua.§- Ut enim §-ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut §-aliquip ex ea commodo consequat. Duis aute irure dolor in §+§rreprehenderit in voluptate velit esse cillum dolore §-eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n Test String1!",
+//            (this.width/2) - 120, this.height/2, 240).setColor(0xFFAAFF).call(this.fontRenderer);
+//
+//        FontHelper.render(Tessellator.instance, "Test String2!", (this.width/2) - 120, FontHelper.getLastEndingY()).call(this.fontRenderer);
+//        FontHelper.render(Tessellator.instance, "Test String3!", (this.width/2) - 120, FontHelper.getLastEndingY()).setColor(0xFF0000).call(this.fontRenderer);
+//        FontHelper.render(Tessellator.instance, "Test String4!", (this.width/2) - 120, FontHelper.getLastEndingY()).call(this.fontRenderer);
+
+//        StringBuilder builder = new StringBuilder();
+//        for (char i = 0; i < 256; i++) {
+//            builder.append(i);
+//            if (i != 0 && i % 16 == 0) {
+//                builder.append("\n");
+//            }
+//        }
+//
+//        FontHelper.renderWidthConstrained(Tessellator.instance, builder, (this.width/2) - 120, FontHelper.getLastEndingY(), Integer.MAX_VALUE).call(this.fontRenderer);
+
+        drawRect((width - 400)/2, 10, (width + 400)/2, 400, 0xFF232323);
+        long start = System.currentTimeMillis();
+        final StringBuilder builder = new StringBuilder("§0§0§0§0§<AAAAFF>");
+        for (int i = 0; i < 1000; i++) {
+            builder.append("a");
+        }
+        builder.append("\n").append(ChatAllowedCharacters.ALLOWED_CHARACTERS);
+        builder.append("\n").append("Obfuscation test: §kTEST STRING §r§<FFAAAA> Static Text");
+        builder.append("\n").append("\tTab");
+        builder.append("\n").append("\t\tTabTab");
+        builder.append("\n").append("   TripleSpace");
+
+        for (Map.Entry<String, Character> entry : ChatEmotes.getEmotes().entrySet()) {
+            builder.append("\n").append(entry.getKey().replace(":", "")).append(": ").append(entry.getValue());
+        }
+
+        builder.append("\n§bLorem ipsum dolor sit amet, §+§3consectetur adipiscing elit, sed do eiusmod tempor incididunt §+§1ut labore et §+§rdolore magna aliqua.§- Ut enim §-ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut §-aliquip ex ea commodo consequat. Duis aute irure dolor in §+§rreprehenderit in voluptate velit esse cillum dolore §-eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \nTest String1!");
+        FontHelper.renderWidthConstrained(Tessellator.instance, builder, (width - 400)/2, (int) (10 + scroll), 400).setAlignment(Alignment.LEFT).setColor(0xFFAAFF).setShadow().call(this.fontRenderer);
+        final long bigStringRenderTime = System.currentTimeMillis() - start;
+        FontHelper.render(Tessellator.instance, "" + bigStringRenderTime/1000f, (width - 400)/2, FontHelper.getLastEndingY() + 20).call(this.fontRenderer);
+
+        final long memTotal = Runtime.getRuntime().totalMemory();
+        final long memFree = Runtime.getRuntime().freeMemory();
+        final long memUsed = memTotal - memFree;
+
+        FontHelper.render(Tessellator.instance, "" + memUsed/(1024 * 1024) + "MB", (width - 400)/2, FontHelper.getLastEndingY() + 20).call(this.fontRenderer);
+
+        final double mouseX = (double) (Mouse.getX() * this.mc.resolution.getScaledWidthScreenCoords()) / this.mc.resolution.getWidthScreenCoords();
+        final double mouseY =  (this.mc.resolution.getScaledHeightScreenCoords() - (double) (Mouse.getY() * this.mc.resolution.getScaledHeightScreenCoords()) / this.mc.resolution.getHeightScreenCoords());
+
+        FontHelper.renderDouble(Tessellator.instance, "Double Precision", mouseX - this.fontRenderer.stringWidthDouble("Double Precision") - 3, mouseY - 6).setShadow().call(this.fontRenderer);
+        FontHelper.render(Tessellator.instance, "Int Precision", (int) (mouseX + 3), (int) (mouseY - 5)).setShadow().call(this.fontRenderer);
+
+//        StringBuilder message = new StringBuilder("<Useless7695> ");
+//        for (char i = '!'; i <= '~'; i++) {
+//            message.append(i);
+//        }
+//        for (char i = '!'; i <= '~'; i++) {
+//            message.append(i);
+//        }
+//        for (char i = '!'; i <= '~'; i++) {
+//            message.append(i);
+//        }
+//
+//        FontHelper.renderWidthConstrained(Tessellator.instance, message, (this.width - 320)/2, 10, 320).setShadow().call(this.fontRenderer);
+    }
+}
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 2207e2514..46fb3619e 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
@@ -68,9 +68,9 @@ public class ScreenGameOver extends Screen
         drawGradientRect(0, 0, width, height, 0x60500000, 0xa0803030);
         GL11.glPushMatrix();
         GL11.glScalef(2.0F, 2.0F, 2.0F);
-        drawStringCentered(font, i18n.translateKey("gui.game_over.label.title"), width / 2 / 2, 30, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey("gui.game_over.label.title"), width / 2 / 2, 30, 0xffffff);
         GL11.glPopMatrix();
-        drawStringCentered(font, i18n.translateKeyAndFormat("gui.game_over.label.score", TextFormatting.YELLOW.toString() + mc.thePlayer.getScore()), width / 2, 100, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKeyAndFormat("gui.game_over.label.score", TextFormatting.YELLOW.toString() + mc.thePlayer.getScore()), width / 2, 100, 0xffffff);
         super.render(mx, my, partialTick);
     }
 
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 1a72d3bc1..bb3b458bb 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
@@ -8,6 +8,7 @@ import net.minecraft.core.item.ItemStack;
 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.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -76,19 +77,19 @@ public class ScreenLabelEditor extends Screen implements ITextField
         final int heightBG = 89;
         drawTexturedModalRect(widthBG, heightBG, 0, 0, 113, 34);
 
-        drawStringCentered(font, screenTitle, width / 2, 40, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, screenTitle, width / 2, 40, 0xffffff);
 
-        drawStringCentered(font, TextFormatting.get(color) + "> " + text + " <", width / 2, 100, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, TextFormatting.get(color) + "> " + text + " <", width / 2, 100, 0xffffff);
 
         boolean drawCursor = !text.isEmpty() && (cursorCounter / 6) % 2 == 0;
         if (drawCursor)
         {
-            int width = font.getStringWidth(editor.getText());
+            int width = MathHelper.ceil(fontRenderer.stringWidthDouble(editor.getText()));
             if (editor.getCursor() < editor.getText().length())
             {
-                width = font.getStringWidth(editor.getText().substring(0, editor.getCursor()));
+                width = MathHelper.ceil(fontRenderer.stringWidthDouble(editor.getText().substring(0, editor.getCursor())));
             }
-            drawString(font, "_", this.width / 2 - font.getStringWidth(editor.getText())/2 + width, 101, 0xffffff);
+            drawStringShadow(fontRenderer, "_", MathHelper.ceil(this.width - fontRenderer.stringWidthDouble(editor.getText())/2) + width, 101, 0xffffff);
         }
         super.render(mx, my, f);
     }
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 1c250c023..35554f56f 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
@@ -357,20 +357,20 @@ public class ScreenMainMenu extends Screen
         GL11.glTranslatef(width / 2 + 140, 80F, 0.0F);
         GL11.glRotatef(-20F, 0.0F, 0.0F, 1.0F);
         float f1 = 1.8F - MathHelper.abs(MathHelper.sin(((float)(System.currentTimeMillis() % 1000L) / 1000F) * MathHelper.PI * 2.0F) * 0.1F);
-        f1 = (f1 * 100F) / (float)(font.getStringWidth(splashText) + 32);
+        f1 = (f1 * 100F) / (float)(fontRenderer.stringWidthDouble(splashText) + 32);
         GL11.glScalef(f1, f1, f1);
-        drawStringCentered(font, splashText, 0, -8, 0xffff00);
+        drawStringCenteredShadow(fontRenderer, splashText, 0, -8, 0xffff00);
         GL11.glPopMatrix();
         int versionTextColor = mc.gameSettings.alphaMenu.value || !mc.mainMenuBackground.isEnabled() ? 0x505050 : 0xFFFFFF;
         if (showBuildTime) {
-            drawString(font, buildTimeString, 2, 2, versionTextColor);
+            drawStringShadow(fontRenderer, buildTimeString, 2, 2, versionTextColor);
         } else {
-            drawString(font, "Better than Adventure! " + Minecraft.VERSION, 2, 2, versionTextColor);
+            drawStringShadow(fontRenderer, "Better than Adventure! " + Minecraft.VERSION, 2, 2, versionTextColor);
         }
         String disclaimer1 = i18n.translateKey("gui.main_menu.label.disclaimer.1");
-        drawString(font, disclaimer1, width - font.getStringWidth(disclaimer1) - 2, height - 20, 0xffffff);
+        drawStringShadow(fontRenderer, disclaimer1, width - MathHelper.ceil(fontRenderer.stringWidthDouble(disclaimer1)) - 2, height - 20, 0xffffff);
         String disclaimer2 = i18n.translateKey("gui.main_menu.label.disclaimer.2");
-        drawString(font, disclaimer2, width - font.getStringWidth(disclaimer2) - 2, height - 10, 0xffffff);
+        drawStringShadow(fontRenderer, disclaimer2, width - MathHelper.ceil(fontRenderer.stringWidthDouble(disclaimer2)) - 2, height - 10, 0xffffff);
         super.render(mx, my, partialTick);
         
     	if(mc.downloadResourcesThread.downloading) {
@@ -378,7 +378,7 @@ public class ScreenMainMenu extends Screen
     		b = b * 0.2 + 0.8;
     		int ib = (int) java.lang.Math.round(b * 255);
     		int color = 0xFF000000 + (ib << 16) + (ib << 8) + (ib);
-    		mc.font.drawCenteredString(
+            drawStringCenteredShadow(mc.font,
                 i18n.translateKeyAndFormat("gui.main_menu.label.downloading_resources", mc.downloadResourcesThread.downloadProgress.get(), mc.downloadResourcesThread.toDownload),
                 width / 2, 16, color);
     	}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenMissingMinecraft.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenMissingMinecraft.java
index de969de3e..0922fba33 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenMissingMinecraft.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenMissingMinecraft.java
@@ -22,19 +22,19 @@ public class ScreenMissingMinecraft extends Screen {
         buttons.add(new ButtonElement(0, width / 2 - 100, height / 4 + 120 + 12, i.translateKey("gui.no_minecraft.button.quit")));
         ClickableLabelElement installLabel = new ClickableLabelElement(1, width / 2 - 170, (height / 4 - 60) + 60 + 64, downloadString, 0x7C99EA);
         buttons.add(installLabel);
-        buttons.add(new ClickableLabelElement(2, 0,  height - font.fontHeight - 4, i.translateKey("gui.main_menu.button.discord"), 0x5865F2));
+        buttons.add(new ClickableLabelElement(2, 0,  height - mc.font.fontHeight() - 4, i.translateKey("gui.main_menu.button.discord"), 0x5865F2));
     }
     @Override
     public void render(int mx, int my, float partialTick)
     {
         I18n i = I18n.getInstance();
         drawBackground(partialTick);
-        drawStringCentered(font, i.translateKey("gui.no_minecraft.label.title"), width / 2, (height / 4 - 60) + 20, 0xffff60);
-        drawString(font, i.translateKey("gui.no_minecraft.label.body.1"), width / 2 - 170, (height / 4 - 60) + 60 + 0, 0xdedede);
-        drawString(font, i.translateKey("gui.no_minecraft.label.body.2"), width / 2 - 170, (height / 4 - 60) + 60 + 18, 0xdedede);
-        drawString(font, i.translateKey("gui.no_minecraft.label.body.3"), width / 2 - 170, (height / 4 - 60) + 60 + 27, 0xdedede);
-        drawString(font, i.translateKey("gui.no_minecraft.label.body.4"), width / 2 - 170, (height / 4 - 60) + 60 + 45, 0xdedede);
-        drawString(font, i.translateKey("gui.no_minecraft.label.body.5"), width / 2 - 170, (height / 4 - 60) + 60 + 54, 0xdedede);
+        drawStringCenteredShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.title"), width / 2, (height / 4 - 60) + 20, 0xffff60);
+        drawStringShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.body.1"), width / 2 - 170, (height / 4 - 60) + 60 + 0, 0xdedede);
+        drawStringShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.body.2"), width / 2 - 170, (height / 4 - 60) + 60 + 18, 0xdedede);
+        drawStringShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.body.3"), width / 2 - 170, (height / 4 - 60) + 60 + 27, 0xdedede);
+        drawStringShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.body.4"), width / 2 - 170, (height / 4 - 60) + 60 + 45, 0xdedede);
+        drawStringShadow(fontRenderer, i.translateKey("gui.no_minecraft.label.body.5"), width / 2 - 170, (height / 4 - 60) + 60 + 54, 0xdedede);
         super.render(mx, my, partialTick);
     }
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenOutOfMemory.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenOutOfMemory.java
index 1c3e59e98..4e49474a1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenOutOfMemory.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenOutOfMemory.java
@@ -13,13 +13,13 @@ public class ScreenOutOfMemory extends Screen
     {
         I18n i18n = I18n.getInstance();
         renderBackground();
-        drawStringCentered(font, i18n.translateKey("gui.out_of_memory.label.title"), width / 2, (height / 4 - 60) + 20, 0xFFFFFF);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.1"), width / 2 - 140, (height / 4 - 60) + 60 + 0, 0xA0A0A0);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.2"), width / 2 - 140, (height / 4 - 60) + 60 + 18, 0xA0A0A0);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.3"), width / 2 - 140, (height / 4 - 60) + 60 + 27, 0xA0A0A0);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.4"), width / 2 - 140, (height / 4 - 60) + 60 + 36, 0xA0A0A0);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.5"), width / 2 - 140, (height / 4 - 60) + 60 + 45, 0xA0A0A0);
-        drawString(font, i18n.translateKey("gui.out_of_memory.label.body.6"), width / 2 - 140, (height / 4 - 60) + 60 + 63, 0xA0A0A0);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.title"), width / 2, (height / 4 - 60) + 20, 0xFFFFFF);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.1"), width / 2 - 140, (height / 4 - 60) + 60 + 0, 0xA0A0A0);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.2"), width / 2 - 140, (height / 4 - 60) + 60 + 18, 0xA0A0A0);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.3"), width / 2 - 140, (height / 4 - 60) + 60 + 27, 0xA0A0A0);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.4"), width / 2 - 140, (height / 4 - 60) + 60 + 36, 0xA0A0A0);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.5"), width / 2 - 140, (height / 4 - 60) + 60 + 45, 0xA0A0A0);
+        drawStringShadow(fontRenderer, i18n.translateKey("gui.out_of_memory.label.body.6"), width / 2 - 140, (height / 4 - 60) + 60 + 63, 0xA0A0A0);
         super.render(mx, my, partialTick);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenPaintingPicker.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenPaintingPicker.java
index 6744edbca..7fc9bbcc5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/ScreenPaintingPicker.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenPaintingPicker.java
@@ -125,8 +125,8 @@ public class ScreenPaintingPicker
 
         glEnable(GL_TEXTURE_2D);
 
-        drawString(font, centerArt.title, centerX - offsetX, centerY + (centerArt.sizeY / 2) * scale + 4, 0xFFFFFFFF);
-        drawString(font, centerArt.artist, centerX - offsetX, centerY + (centerArt.sizeY / 2) * scale + 16, 0x7F7F7F7F);
+        drawStringShadow(fontRenderer, centerArt.title, centerX - offsetX, centerY + (centerArt.sizeY / 2) * scale + 4, 0xFFFFFFFF);
+        drawStringShadow(fontRenderer, centerArt.artist, centerX - offsetX, centerY + (centerArt.sizeY / 2) * scale + 16, 0x7F7F7F7F);
 
         glEnable(GL_BLEND);
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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 418ed37f2..733ace42f 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
@@ -119,11 +119,11 @@ public class ScreenPause extends Screen
             float f1 = ((float)(updateCounter % 10) + partialTick) / 10F;
             f1 = MathHelper.sin(f1 * MathHelper.PI * 2.0F) * 0.2F + 0.8F;
             int k = (int)(255F * f1);
-            drawString(font, i.translateKey("gui.ingame_menu.label.saving"), 8, height - 16, k << 16 | k << 8 | k);
+            drawStringShadow(fontRenderer, i.translateKey("gui.ingame_menu.label.saving"), 8, height - 16, k << 16 | k << 8 | k);
         }
-        drawStringCentered(font, i.translateKey("gui.ingame_menu.label.title"), width / 2, 40, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i.translateKey("gui.ingame_menu.label.title"), width / 2, 40, 0xffffff);
         String score = TextFormatting.YELLOW.toString() + mc.thePlayer.getScore();
-        drawStringCentered(font, i.translateKeyAndFormat("gui.ingame_menu.label.score", score), width / 2, 56, 0xfefefe);
+        drawStringCenteredShadow(fontRenderer, i.translateKeyAndFormat("gui.ingame_menu.label.score", score), width / 2, 56, 0xfefefe);
         super.render(mx, my, partialTick);
     }
 
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 f0707cedd..e26e6b12b 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
@@ -5,7 +5,6 @@ import net.minecraft.client.input.controller.ControllerInput;
 import net.minecraft.client.util.helper.FileOpener;
 import net.minecraft.core.Global;
 import net.minecraft.core.util.helper.MathHelper;
-import net.minecraft.core.util.helper.Utils;
 import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.season.Seasons;
 import org.lwjgl.input.Keyboard;
@@ -450,7 +449,7 @@ public class ScreenPhotoMode extends Screen
             }
         }
         
-        if (showHelpText) drawStringCentered(font, I18n.getInstance().translateKey("gui.photo_mode.label.mouse_hint"), width / 2, height - 36, 0xFFFFFF);
+        if (showHelpText) drawStringCenteredShadow(fontRenderer, I18n.getInstance().translateKey("gui.photo_mode.label.mouse_hint"), width / 2, height - 36, 0xFFFFFF);
     }
 
     private void updateButtonsText()
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 6095d0a70..6e404da79 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
@@ -213,7 +213,7 @@ public class ScreenSelectServer extends Screen {
 	@Override
 	public void render(int mx, int my, float partialTick) {
 		worldSlotContainer.render(mx, my, partialTick);
-		drawStringCentered(font, screenTitle, width / 2, 20, 0xffffff);
+		drawStringCenteredShadow(fontRenderer, screenTitle, width / 2, 20, 0xffffff);
 		super.render(mx, my, partialTick);
 	}
 	
@@ -266,31 +266,31 @@ public class ScreenSelectServer extends Screen {
 			String line1 = server.nickname;
 			String line2 = server.address;
 
-			drawString(font, line1, x + 2, y + 1, 0xffffff);
-			if (server.showIp) drawString(font, line2, x + 2, y + 12 + 10, 0x404040);
+			drawStringShadow(fontRenderer, line1, x + 2, y + 1, 0xffffff);
+			if (server.showIp) drawStringShadow(fontRenderer, line2, x + 2, y + 12 + 10, 0x404040);
 			if (server.isUp && server.protocolVersion != Global.MP_PROTOCOL_VERSION) {
 				String outdated = I18n.getInstance().translateKey("gui.select_server.label.outdated");
-				int width = font.getStringWidth(outdated);
-				drawString(font, outdated, x + 220 - width - 4, y + 1, 0xFF0000);
-				width = font.getStringWidth(server.version);
-				drawString(font, server.version, x + 220 - width - 4, y + 12, 0xFF0000);
-				drawString(font, server.motd, x + 2, y + 12, 0x808080);
+				int width = MathHelper.ceil(fontRenderer.stringWidthDouble(outdated));
+				drawStringShadow(fontRenderer, outdated, x + 220 - width - 4, y + 1, 0xFF0000);
+				width = MathHelper.ceil(fontRenderer.stringWidthDouble(server.version));
+				drawStringShadow(fontRenderer, server.version, x + 220 - width - 4, y + 12, 0xFF0000);
+				drawStringShadow(fontRenderer, server.motd, x + 2, y + 12, 0x808080);
 			} else if (server.isUp) {
 				String latency = server.latency + "ms";
-				int width = font.getStringWidth(latency);
+				int width = MathHelper.ceil(fontRenderer.stringWidthDouble(latency));
 				float green = 1.0f - MathHelper.clamp((float)server.latency / 500.0F, 0.0F, 1.0F);
 				float red = 1.0F - green;
 				int argb = 0xFF000000 | (int)(255.0F * red) << 16 | (int)(255.0F * green) << 8;
 
-				drawString(font, latency, x + 220 - width - 4, y + 1, argb);
+				drawStringShadow(fontRenderer, latency, x + 220 - width - 4, y + 1, argb);
 				String players = server.currentPlayers + "/" + server.maxPlayers;
-				width = font.getStringWidth(players);
-				drawString(font, players, x + 220 - width - 4, y + 12, 0x808080);
-				drawString(font, server.motd, x + 2, y + 12, 0x808080);
+				width = MathHelper.ceil(fontRenderer.stringWidthDouble(players));
+				drawStringShadow(fontRenderer, players, x + 220 - width - 4, y + 12, 0x808080);
+				drawStringShadow(fontRenderer, server.motd, x + 2, y + 12, 0x808080);
 			} else {
 				String down = I18n.getInstance().translateKey("gui.select_server.label.down");
-				int width = font.getStringWidth(down);
-				drawString(font, down, x + 220 - width - 4, y + 1, 0xFF0000);
+				int width = MathHelper.ceil(fontRenderer.stringWidthDouble(down));
+				drawStringShadow(fontRenderer, down, x + 220 - width - 4, y + 1, 0xFF0000);
 			}
 		}
 	}
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 84bcd719c..e4b9000c0 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
@@ -256,7 +256,7 @@ public class ScreenSelectWorld extends Screen
     public void render(int mx, int my, float partialTick)
     {
         worldSlotContainer.render(mx, my, partialTick);
-        drawStringCentered(font, stringTitle, width / 2, 20, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, stringTitle, width / 2, 20, 0xffffff);
         super.render(mx, my, partialTick);
     }
 
@@ -345,9 +345,9 @@ public class ScreenSelectWorld extends Screen
                 }
             }
 
-            drawString(font, s, x + 2, y + 1, 0xffffff);
-            drawString(font, s1, x + 2, y + 12, 0x808080);
-            drawString(font, s2, x + 2, y + 12 + 10, 0x808080);
+            drawStringShadow(fontRenderer, s, x + 2, y + 1, 0xffffff);
+            drawStringShadow(fontRenderer, s1, x + 2, y + 12, 0x808080);
+            drawStringShadow(fontRenderer, s2, x + 2, y + 12 + 10, 0x808080);
         }
     }
 }
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 9a423b1d7..9c63e80d4 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
@@ -151,7 +151,7 @@ public class ScreenSignEditor extends Screen
             }
         }
         renderBackground();
-        drawStringCentered(font, screenTitle, width / 2, 40, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, screenTitle, width / 2, 40, 0xffffff);
         GL11.glPushMatrix();
         GL11.glTranslatef((float) width / 2, 0.0F, 50F);
         float scale = 93.75F;
@@ -190,7 +190,7 @@ public class ScreenSignEditor extends Screen
         entitySign.lineBeingEdited = -1;
         GL11.glPopMatrix();
         
-        drawStringCentered(font, I18n.getInstance().translateKey(entitySign.getPicture().getLanguageKey()), width / 2, 100 + 50 + yOffset, 0xFFFFFF);
+        drawStringCenteredShadow(fontRenderer, I18n.getInstance().translateKey(entitySign.getPicture().getLanguageKey()), width / 2, 100 + 50 + yOffset, 0xFFFFFF);
 
         super.render(mx, my, partialTick);
     }
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 cda236899..a87899095 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
@@ -3,6 +3,7 @@ package net.minecraft.client.gui;
 import net.minecraft.client.gui.modelviewer.elements.ListenerButtonElement;
 import net.minecraft.client.gui.modelviewer.elements.ListenerTextFieldElement;
 import net.minecraft.client.gui.modelviewer.elements.IListenerElement;
+import net.minecraft.client.render.font.Alignment;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.sound.SoundEngine;
 import net.minecraft.client.sound.SoundEvent;
@@ -10,7 +11,7 @@ import net.minecraft.client.sound.SoundRepository;
 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.Utils;
+import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.Nullable;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -156,21 +157,16 @@ public class ScreenSoundTest extends Screen {
 
         super.render(mx, my, partialTick);
 
-        font.drawCenteredString(I18n.getInstance().translateKey("gui.sound_test.label.title"), width/2, 5, 0xFFFFFF);
+        drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey("gui.sound_test.label.title"), width/2, 5, 0xFFFFFF);
 
-        String msg = I18n.getInstance().translateKey("gui.sound_test.label.select_entry");
-        font.drawString(msg, leftEntry.getX() - BUTTON_SPACING - font.getStringWidth(msg), leftEntry.getY() + 6, 0xFFFFFF);
+        final String msg = I18n.getInstance().translateKey("gui.sound_test.label.select_entry");
+        drawStringNoShadow(this.fontRenderer, msg, leftEntry.getX() - BUTTON_SPACING - MathHelper.ceil(fontRenderer.stringWidthDouble(msg)), leftEntry.getY() + 6, 0xFFFFFF);
 
         StringBuilder builder = new StringBuilder();
-        builder.append(font.wrapFormattedStringToWidth(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.id", currentEntry == null ? null : currentEntry.getEventID()), width - 10)).append("\n");
-        builder.append(font.wrapFormattedStringToWidth(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.subtitle", currentEntry == null ? null : currentEntry.getSubtitleKey(), currentEntry == null ? null : currentEntry.getSubtitleTranslated()), width - 10)).append("\n");
-//        builder.append(fontRenderer.wrapFormattedStringToWidth(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.url", String.valueOf(currentEntry == null ? null : (showURL ? currentEntry.url : "REDACTED"))), width - 10)).append("\n");
-        String[] lines = builder.toString().split("\n");
-        int y = top + 30;
-        for (String line : lines) {
-            font.drawString(line, 5, y, 0xBBBBBB);
-            y += 10;
-        }
+        builder.append(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.id", currentEntry == null ? null : currentEntry.getEventID())).append("\n");
+        builder.append(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.subtitle", currentEntry == null ? null : currentEntry.getSubtitleKey(), currentEntry == null ? null : currentEntry.getSubtitleTranslated())).append("\n");
+//        builder.append(I18n.getInstance().translateKeyAndFormat("gui.sound_test.label.url", String.valueOf(currentEntry == null ? null : (showURL ? currentEntry.url : "REDACTED")))).append("\n");
+        fontRenderer.renderWidthConstrained(Tessellator.instance, builder, 5, top + 30, 0, true, 0xBBBBBB, width - 10, Alignment.LEFT, null, null, null);
     }
     @Override
     public void renderBackground() {
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 0f5b492d5..51c21e870 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
@@ -9,6 +9,7 @@ import net.minecraft.core.lang.I18n;
 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.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL12;
@@ -98,7 +99,7 @@ public class ScreenStats extends Screen {
 	public void render(int mx, int my, float partialTick)
     {
         selectionList.render(mx, my, partialTick);
-        drawStringCentered(font, title, width / 2, 20, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, title, width / 2, 20, 0xffffff);
         super.render(mx, my, partialTick);
     }
 
@@ -236,11 +237,11 @@ public class ScreenStats extends Screen {
             if(statItem != null)
             {
                 String s = statItem.getFormattedValue(statsCounter.readStat(statItem));
-                drawString(font, s, x - font.getStringWidth(s), y + 5, white ? 0xffffff : 0x909090);
+                drawStringShadow(fontRenderer, s, x - MathHelper.ceil(fontRenderer.stringWidthDouble(s)), y + 5, white ? 0xffffff : 0x909090);
             } else
             {
                 String s1 = "-";
-                drawString(font, s1, x - font.getStringWidth(s1), y + 5, white ? 0xffffff : 0x909090);
+                drawStringShadow(fontRenderer, s1, x - MathHelper.ceil(fontRenderer.stringWidthDouble(s1)), y + 5, white ? 0xffffff : 0x909090);
             }
         }
 
@@ -348,9 +349,9 @@ public class ScreenStats extends Screen {
         protected void renderItem(int index, int x, int y, int height, Tessellator tessellator)
         {
             Stat stat = StatList.basicStats.get(index);
-            drawString(font, stat.getStatName(), x + 2, y + 1, index % 2 != 0 ? 0x909090 : 0xffffff);
+            drawStringShadow(fontRenderer, stat.getStatName(), x + 2, y + 1, index % 2 != 0 ? 0x909090 : 0xffffff);
             String s = stat.getFormattedValue(statsCounter.readStat(stat));
-            drawString(font, s, (x + 2 + 213) - font.getStringWidth(s), y + 1, index % 2 != 0 ? 0x909090 : 0xffffff);
+            drawStringShadow(fontRenderer, s, (x + 2 + 213) - MathHelper.ceil(fontRenderer.stringWidthDouble(s)), y + 1, index % 2 != 0 ? 0x909090 : 0xffffff);
         }
     }
 
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 d266bd799..58517d278 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
@@ -8,7 +8,6 @@ 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 net.minecraft.core.util.helper.Utils;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
@@ -119,7 +118,7 @@ public class ScreenTextureViewer extends Screen {
     public void render(int mx, int my, float partialTick) {
         renderBackground();
 
-        font.drawCenteredString(I18n.getInstance().translateKey("gui.texture_viewer.label.title"), width/2, 5, 0xFFFFFF);
+        drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey("gui.texture_viewer.label.title"), width/2, 5, 0xFFFFFF);
 
         List<Integer> textureList = GLAllocation.textureNames;
         int id = texIndex % textureList.size();
@@ -187,9 +186,9 @@ public class ScreenTextureViewer extends Screen {
         GL11.glDisable(GL11.GL_DEPTH_TEST);
 
         if (drawText) {
-            font.drawString("Tex ID: " + id , 1, top + 1, 0xFFFFFF, true);
-            font.drawString("Tex Width: " + texWidth, 1, top + 11, 0xFFFFFF, true);
-            font.drawString("Tex Height: " + texHeight, 1, top + 21, 0xFFFFFF, true);
+            drawStringShadow(this.fontRenderer, "Tex ID: " + id , 1, top + 1, 0xFFFFFF);
+            drawStringShadow(this.fontRenderer, "Tex Width: " + texWidth, 1, top + 11, 0xFFFFFF);
+            drawStringShadow(this.fontRenderer, "Tex Height: " + texHeight, 1, top + 21, 0xFFFFFF);
 
             String s;
             if (t == null) {
@@ -200,7 +199,7 @@ public class ScreenTextureViewer extends Screen {
             String[] lines = s.split("\n");
             int yOff = top + 31;
             for (String line : lines) {
-                font.drawString(line, 1, yOff, 0xFFFFFF, true);
+                drawStringShadow(fontRenderer, line, 1, yOff, 0xFFFFFF);
                 yOff += 10;
             }
         }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/SliderElement.java b/game/client/src/main/java/net/minecraft/client/gui/SliderElement.java
index a700f9a70..0f323dda2 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/SliderElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/SliderElement.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.gui;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import org.lwjgl.opengl.GL11;
@@ -65,8 +64,7 @@ public class SliderElement extends ButtonElement {
 	{
 		if (!visible) return;
 
-		Font font = mc.font;
-		boolean mouseOver = mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height;
+				boolean mouseOver = mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height;
 		int state = getButtonState(mouseOver);
 
 		GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
@@ -104,7 +102,7 @@ public class SliderElement extends ButtonElement {
 				textColor = 0xFFFFA0;
 				break;
 		}
-		drawStringCentered(font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
+		drawStringCenteredShadow(mc.font, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, textColor);
 	}
 
 	@Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/SwitchElement.java b/game/client/src/main/java/net/minecraft/client/gui/SwitchElement.java
index 138684442..0c110995f 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/SwitchElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/SwitchElement.java
@@ -1,7 +1,6 @@
 package net.minecraft.client.gui;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import org.lwjgl.opengl.GL11;
@@ -61,7 +60,6 @@ public class SwitchElement
     public void drawButton(Minecraft mc, int mouseX, int mouseY) {
         if (!visible) return;
 
-        Font font = mc.font;
         boolean mouseOver = mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height;
         int state = getButtonState(mouseOver);
         int xBar = on ? (width / 3) + 1 : 0;
@@ -101,6 +99,6 @@ public class SwitchElement
                 textColor = 0xFFFFA0;
                 break;
         }
-        drawStringCentered(font, displayString, xPosition + xBar + width / 3, yPosition + (height - 8) / 2, textColor);
+        drawStringCenteredShadow(mc.font, displayString, xPosition + xBar + width / 3, yPosition + (height - 8) / 2, textColor);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java b/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java
index c5f4a9852..617eeccf8 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/TextFieldElement.java
@@ -4,8 +4,9 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.keyboard.ScreenKeyboard;
 import net.minecraft.client.gui.text.TextFieldEditor;
 import net.minecraft.client.input.InputType;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.window.CursorShape;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.input.Keyboard;
 
 import net.minecraft.client.gui.text.ITextField;
@@ -13,7 +14,7 @@ import net.minecraft.client.gui.text.ITextField;
 public class TextFieldElement extends Gui implements ITextField
 {
 	
-    private final Font font;
+    private final FontRenderer fontRenderer;
     public int xPosition;
     public int yPosition;
     public final int width;
@@ -29,12 +30,12 @@ public class TextFieldElement extends Gui implements ITextField
     public boolean drawBackground = true;
     private TextFieldEditor editor;
 
-    public TextFieldElement(Screen parent, Font font, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder)
+    public TextFieldElement(Screen parent, FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder)
     {
         isFocused = false;
         isEnabled = true;
         this.parent = parent;
-        this.font = font;
+        this.fontRenderer = fontRenderer;
         this.xPosition = xPosition;
         this.yPosition = yPosition;
         this.width = width;
@@ -131,40 +132,40 @@ public class TextFieldElement extends Gui implements ITextField
         }
         if (text.isEmpty() && !isFocused)
         {
-            drawString(font, placeholder, xPosition + 4, yPosition + (height - 8) / 2, 0x5f5f5f);
+            drawStringShadow(fontRenderer, placeholder, xPosition + 4, yPosition + (height - 8) / 2, 0x5f5f5f);
         }
 
         if(isEnabled)
         {
             boolean drawCursor = isFocused && (cursorCounter / 6) % 2 == 0;
             int cursor = editor.getCursor();
-            int maxDisplayableChars = this.width / font.getCharWidth('_');
+            int maxDisplayableChars = this.width / fontRenderer.charWidth('_');
 
             if(text.length() <= maxDisplayableChars-1){
-                drawString(font, text, xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                drawStringShadow(fontRenderer, text, xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
             } else {
                 //only draw the part of the string that's maxDisplayableChars chars around the cursor
                 int begin = Math.max(0,cursor - maxDisplayableChars);
                 int end = Math.max(maxDisplayableChars,Math.min(text.length(),cursor));
-                drawString(font, text.substring(begin, end), xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                drawStringShadow(fontRenderer, text.substring(begin, end), xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
             }
             if (drawCursor)
             {
-                int width = font.getStringWidth(text);
+                int width = MathHelper.ceil(fontRenderer.stringWidthDouble(text));
                 if (cursor < text.length())
                 {
-                    width = font.getStringWidth(text.substring(0, cursor));
+                    width = MathHelper.ceil(fontRenderer.stringWidthDouble(text.substring(0, cursor)));
                 }
                 if(width >= this.width-4){
                     // width of the text box - the width of the last character
-                    width = (this.width-4) - font.getStringWidth(text.substring(text.length()-2,text.length()-1));
+                    width = (this.width-4) - MathHelper.ceil(fontRenderer.stringWidthDouble(text.substring(text.length()-2,text.length()-1)));
                 }
-                drawString(font, "_", xPosition + 4 + width, yPosition + (height - 8) / 2 + 1, 0xE0E0E0);
+                drawStringShadow(fontRenderer, "_", xPosition + 4 + width, yPosition + (height - 8) / 2 + 1, 0xE0E0E0);
             }
         }
         else
         {
-            drawString(font, text, xPosition + 4, yPosition + (height - 8) / 2, 0x707070);
+            drawStringShadow(fontRenderer, text, xPosition + 4, yPosition + (height - 8) / 2, 0x707070);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java
index 564048e0b..4168675e6 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/TooltipElement.java
@@ -7,6 +7,9 @@ import com.google.gson.JsonParser;
 import com.google.gson.stream.JsonReader;
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.texturepack.TexturePack;
@@ -15,12 +18,12 @@ import net.minecraft.core.WeightedRandomBag;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryTrommel;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.item.ItemStack;
-import net.minecraft.client.render.Font;
 import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.core.player.inventory.slot.SlotResult;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.client.gui.guidebook.SlotGuidebook;
+import net.minecraft.core.util.helper.MathHelper;
 import org.jetbrains.annotations.NotNull;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -34,10 +37,8 @@ import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 public class TooltipElement extends Gui
 {
@@ -47,37 +48,44 @@ public class TooltipElement extends Gui
     protected final static Style defaultStyle = new Style("default", "default", 3, 3, 3, 3);
 
     Minecraft mc;
-    Font fr;
+    FontRenderer fontRenderer;
 
     public TooltipElement(Minecraft mc)
     {
         this.mc = mc;
-        this.fr = mc.font;
+        this.fontRenderer = mc.font;
     }
     public static final int BASE_PADDING = 3;
     public static final int LINE_SPACING = 3;
 
-    public void render(String string, int x, int y, int offsetX, int offsetY)
+    public void render(final CharSequence string, final int x, final int y, final int offsetX, final int offsetY) {
+        render(string, x, y, offsetX, offsetY, -1, -1, true);
+    }
+    public void render(final CharSequence chars, int x, int y, int offsetX, int offsetY, int maxWidth, int maxHeight, boolean canOffset)
     {
-        String[] lines = string.split("\n");
-        if(lines.length == 0) return;
+        maxWidth = maxWidth == -1 ? Integer.MAX_VALUE : maxWidth;
+        maxHeight = maxHeight == -1 ? Integer.MAX_VALUE : maxHeight;
 
+        final List<String> lines = new ArrayList<>();
+        this.fontRenderer.splitCharsIntoLines(chars, maxWidth, lines);
         int width = 0;
-        for (String line : lines)
+        for (final String line : lines)
         {
-            width = Math.max(width, fr.getStringWidth(line));
+            width = Math.max(width, this.fontRenderer.stringWidth(line) - 1);
         }
 
-        int height = lines.length * 8 + (lines.length - 1) * LINE_SPACING;
+        final int height = MathHelper.ceil(this.fontRenderer.heightOfLines(lines, maxWidth) - 1);
 
         // Flip tooltip X if it goes offscreen to the right
-        if(x + offsetX + width + BASE_PADDING * 2 > mc.resolution.getScaledWidthScreenCoords())
+        if(canOffset && x + offsetX + width > this.mc.resolution.getScaledWidthScreenCoords())
         {
             offsetX = -offsetX - width;
         }
 
-        // Move tooltip up when it goes offscreen to the bottom
-        offsetY -= Math.max(0, y + height + offsetY + BASE_PADDING * 2 - mc.resolution.getScaledHeightScreenCoords());
+        if (canOffset) {
+            // Move tooltip up when it goes offscreen to the bottom
+            offsetY -= Math.max(0, y + height + offsetY - this.mc.resolution.getScaledHeightScreenCoords());
+        }
 
 
         x += offsetX;
@@ -86,20 +94,17 @@ public class TooltipElement extends Gui
         final int padding = getPadding();
 
         drawBackground(x, y, x + width, y + height);
+//        drawRect(x, y, x + width, y + height, 0xFFFFFFFF);
 
-
-        for(int i = 0; i < lines.length; i++)
-        {
-            fr.drawStringWithShadow(lines[i], x + padding, y + padding + i * (8 + LINE_SPACING), 0xFFFFFF);
-        }
+        FontHelper.renderWidthConstrained(Tessellator.instance, chars, x + padding, y + padding, maxWidth).call(this.fontRenderer);
     }
     public int getPadding(){
-        return BASE_PADDING;
+        return 0;
     }
     public int[] drawBackground(int x, int y, int offsetX, int offsetY, int width, int height){
 //        int targetOffset = 0;
         // Flip tooltip X if it goes offscreen to the right
-        if(x + offsetX + width + BASE_PADDING * 2 > mc.resolution.getScaledWidthScreenCoords())
+        if(x + offsetX + width > mc.resolution.getScaledWidthScreenCoords())
         {
 //            int _offsetX = offsetX;
             offsetX = -offsetX - width;
@@ -107,7 +112,7 @@ public class TooltipElement extends Gui
         }
 
         // Move tooltip up when it goes offscreen to the bottom
-        offsetY -= Math.max(0, y + height + offsetY + BASE_PADDING * 2 - mc.resolution.getScaledHeightScreenCoords());
+        offsetY -= Math.max(0, y + height + offsetY - mc.resolution.getScaledHeightScreenCoords());
 
         x += offsetX;
         y += offsetY;
@@ -122,8 +127,18 @@ public class TooltipElement extends Gui
             GL11.glEnable(GL11.GL_BLEND);
             GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
 
-            drawGuiIcon(minX, minY, maxX - minX + BASE_PADDING * 2, maxY - minY + BASE_PADDING * 2, style.getInnerIcon());
-            drawGuiIcon(minX - style.paddingLeft, minY - style.paddingTop, maxX - minX + BASE_PADDING * 2 + style.paddingLeft + style.paddingRight, maxY - minY + BASE_PADDING * 2 + style.paddingTop + style.paddingBottom, style.getBorderIcon());
+            drawGuiIcon(
+                minX - 2,
+                minY - 2,
+                maxX - minX + 4,
+                maxY - minY + 4,
+                style.getInnerIcon());
+            drawGuiIcon(
+                minX - 2 - style.paddingLeft,
+                minY - 2 - style.paddingTop,
+                maxX - minX + 4 + style.paddingLeft + style.paddingRight,
+                maxY - minY + 4 + style.paddingTop + style.paddingBottom,
+                style.getBorderIcon());
 
             GL11.glDisable(GL11.GL_BLEND);
         }
@@ -277,6 +292,7 @@ public class TooltipElement extends Gui
         packs.add(packList.getDefaultTexturePack());
         packs.addAll(packList.selectedPacks);
         final Collection<String> styleIds = new ArrayList<>();
+        styleIds.add("default");
         for (int i = packs.size() - 1; i >= 0; i--) {
             final TexturePack pack = packs.get(i);
             try (final InputStream stylesStream = pack.getResourceAsStream("/assets/minecraft/textures/gui/sprites/tooltip/styles.json")) {
@@ -298,7 +314,6 @@ public class TooltipElement extends Gui
                 LOGGER.error("Error occurred while parsing 'styles.json'!", runtimeException);
             }
         }
-        styleIds.add("default");
 
         for (final String styleId : styleIds) {
             JsonObject properties = null;
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 2a1331a24..241dada68 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
@@ -11,6 +11,7 @@ import net.minecraft.client.gui.achievements.data.AchievementPages;
 import net.minecraft.client.gui.options.OptionsButtonElement;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.Scissor;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -415,9 +416,8 @@ public class ScreenAchievements extends Screen
             drawPagesListScrollBar(mx, my);
 
             if (hoveredPage != null){
-                String msg = font.wrapFormattedStringToWidth(hoveredPage.getDescription(), TOOLTIP_BOX_WIDTH_MIN);
-                msg += "\n" + TextFormatting.LIGHT_GRAY + I18n.getInstance().translateKeyAndFormat("gui.achievements.label.completion",  Math.round(hoveredPage.getCompletionFraction(statsCounter) * 100) + "%");
-                tooltip.render(msg, mx, my, TOOLTIP_OFF_X, TOOLTIP_OFF_Y);
+                final String msg = this.hoveredPage.getDescription() + "\n" + TextFormatting.LIGHT_GRAY + I18n.getInstance().translateKeyAndFormat("gui.achievements.label.completion",  Math.round(hoveredPage.getCompletionFraction(statsCounter) * 100) + "%");
+                this.tooltip.render(msg, mx, my, TOOLTIP_OFF_X, TOOLTIP_OFF_Y, TOOLTIP_BOX_WIDTH_MIN, -1, true);
             }
         }
 
@@ -445,7 +445,7 @@ public class ScreenAchievements extends Screen
     }
 
     protected void renderLabels() {
-        font.drawCenteredString(I18n.getInstance().translateKey("gui.achievements.label.title")/* + " " + viewportZoom + " X:" + currentShiftX + ", Y:" + currentShiftY*/, width/2, 5 , 0xFFFFFF);
+        drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey("gui.achievements.label.title")/* + " " + viewportZoom + " X:" + currentShiftX + ", Y:" + currentShiftY*/, width/2, 5 , 0xFFFFFF);
     }
 
 
@@ -856,25 +856,25 @@ public class ScreenAchievements extends Screen
         final int padding = tooltip.getPadding();
         int[] boxRender;
         if(statsCounter.canUnlock(achievement)) { // Can unlock/ is unlocked
-            int boxWidth = Math.max(font.getStringWidth(name), TOOLTIP_BOX_WIDTH_MIN);
-            int boxHeight = font.getHeightOfConstrainedString(desc, boxWidth);
+            int boxWidth = Math.max(MathHelper.ceil(this.fontRenderer.stringWidthDouble(name)), TOOLTIP_BOX_WIDTH_MIN);
+            int boxHeight = MathHelper.ceil(this.fontRenderer.heightOfConstrainedChars(desc, boxWidth));
             if(statsCounter.isUnlocked(achievement)) {
                 boxHeight += 12;
             }
             boxRender = tooltip.drawBackground(mouseX, mouseY, TOOLTIP_OFF_X, TOOLTIP_OFF_Y, boxWidth + 3, boxHeight + 3 + 12);
-            font.drawStringIntoConstrainedBlock(desc, boxRender[0] + padding, boxRender[1] + 12 + padding, boxWidth, 0xffa0a0a0);
+            FontHelper.renderWidthConstrained(Tessellator.instance, desc, boxRender[0] + padding, boxRender[1] + 12 + padding, boxWidth).setColor(0xffa0a0a0).call(this.fontRenderer);
             if(statsCounter.isUnlocked(achievement)) { // Add taken string to bottom
-                font.drawStringWithShadow(I18n.getInstance().translateKey("gui.achievements.label.taken"), boxRender[0] + padding, boxRender[1] + boxHeight + 8 + padding, 0xff9090ff);
+                drawStringShadow(fontRenderer, I18n.getInstance().translateKey("gui.achievements.label.taken"), boxRender[0] + padding, boxRender[1] + boxHeight + 8 + padding, 0xff9090ff);
             }
         } else { // Not unlocked so darken
-            int boxWidth = Math.max(font.getStringWidth(name), TOOLTIP_BOX_WIDTH_MIN);
+            int boxWidth = Math.max(MathHelper.ceil(fontRenderer.stringWidthDouble(name)), TOOLTIP_BOX_WIDTH_MIN);
             String msg = I18n.getInstance().translateKeyAndFormat("gui.achievements.label.requires", achievement.parent.getStatName());
-            int boxHeight = font.getHeightOfConstrainedString(msg, boxWidth);
+            int boxHeight = MathHelper.ceil(fontRenderer.heightOfConstrainedChars(msg, boxWidth));
             boxRender = tooltip.drawBackground(mouseX, mouseY, TOOLTIP_OFF_X, TOOLTIP_OFF_Y, boxWidth + 3, boxHeight + 3 + 12);
-            font.drawStringIntoConstrainedBlock(msg, boxRender[0] + padding, boxRender[1] + 12 + padding, boxWidth, 0xff705050);
+            FontHelper.renderWidthConstrained(Tessellator.instance, msg, boxRender[0] + padding, boxRender[1] + 12 + padding, boxWidth).setColor(0xff705050).call(this.fontRenderer);
         }
         int color = statsCounter.canUnlock(achievement) ? achievement.getType().colorName : achievement.getType().colorNameLocked;
-        font.drawStringWithShadow(name, boxRender[0] + padding, boxRender[1] + padding, color);
+        drawStringShadow(fontRenderer, name, boxRender[0] + padding, boxRender[1] + padding, color);
     }
     public boolean drawSidebar(){
         return AchievementPageRegistry.getInstance().getPages().size() > 1;
@@ -914,7 +914,7 @@ public class ScreenAchievements extends Screen
                 GL11.glColor4f(1f, 1f, 1f, 1f);
                 drawGuiIcon(x + 8, y2 + (PAGE_BUTTON_HEIGHT / 2) - 9 + 8, 11, 11, TextureRegistry.getTexture("minecraft:gui/screen/achievement/star"));
             }
-            mc.font.drawStringWithShadow(name, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
+            drawStringShadow(this.fontRenderer, name, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
             y2 += PAGE_BUTTON_HEIGHT;
         }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatEmotePicker.java b/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatEmotePicker.java
index ab644a0eb..7d95ca20e 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatEmotePicker.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatEmotePicker.java
@@ -125,6 +125,6 @@ public class GuiElementChatEmotePicker extends Gui {
             color = 0xffffffa0;
         }
 
-        drawStringCentered(mc.font, String.valueOf(c), x + CELL_WIDTH / 2, y + (CELL_HEIGHT / 2 - 4), color);
+        drawStringCenteredShadow(mc.font, String.valueOf(c), x + CELL_WIDTH / 2, y + (CELL_HEIGHT / 2 - 4), color);
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatSuggestions.java b/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatSuggestions.java
index fa1b9f38d..8c7501e44 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatSuggestions.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/chat/GuiElementChatSuggestions.java
@@ -21,7 +21,9 @@ import net.minecraft.client.gui.hud.component.ComponentAnchor;
 import net.minecraft.client.gui.text.ITextField;
 import net.minecraft.client.gui.text.TextFieldEditor;
 import net.minecraft.client.net.command.ClientCommandSource;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.net.command.*;
 import net.minecraft.core.net.command.util.CommandHelper;
 import net.minecraft.core.net.packet.PacketRequestCommandManager;
@@ -44,7 +46,7 @@ public class GuiElementChatSuggestions extends Gui {
     private final TextFieldEditor editor;
     private final ITextField textField;
     private final Minecraft mc;
-    private final Font fontRenderer;
+    private final FontRenderer fontRenderer;
     private final CommandSource commandSource;
     private final PositionSupplier<Integer> xSupplier;
     private final PositionSupplier<Integer> ySupplier;
@@ -129,7 +131,7 @@ public class GuiElementChatSuggestions extends Gui {
         }
     }
 
-    private void renderSuggestions(Font fontRenderer, String message, int start) {
+    private void renderSuggestions(FontRenderer fontRenderer, String message, int start) {
         int mouseX = getScaledMouseX(this.mc);
         int mouseY = getScaledMouseY(this.mc) - 1;
 
@@ -137,8 +139,8 @@ public class GuiElementChatSuggestions extends Gui {
 
         int largestSuggestion = 0;
         for (Suggestion suggestion : this.suggestions)
-            if (fontRenderer.getStringWidth(suggestion.getText()) > largestSuggestion)
-                largestSuggestion = fontRenderer.getStringWidth(suggestion.getText());
+            if (fontRenderer.stringWidth(suggestion.getText()) > largestSuggestion)
+                largestSuggestion = fontRenderer.stringWidth(suggestion.getText());
 
         leftMargin -= (int) (this.anchor.xPosition * (largestSuggestion + 2));
 
@@ -163,9 +165,9 @@ public class GuiElementChatSuggestions extends Gui {
                 colorCode = TextFormatting.LIGHT_GRAY.toString();
             }
 
-            int textX = (int) (leftMargin + 1 + (this.anchor.xPosition * (largestSuggestion - fontRenderer.getStringWidth(suggestionText))));
+            int textX = (int) (leftMargin + 1 + (this.anchor.xPosition * (largestSuggestion - fontRenderer.stringWidth(suggestionText))));
 
-            fontRenderer.drawStringWithShadow(colorCode + suggestionText, textX, minY + suggestionBoxHeight - suggestionHeight + 3, 0xE0E0E0);
+            FontHelper.render(Tessellator.instance, colorCode + suggestionText, textX, minY + suggestionBoxHeight - suggestionHeight + 3).setShadow().setColor(0xE0E0E0).call(fontRenderer);
         }
 
         if (this.isHoveringOverSuggestions(mouseX, mouseY) && this.suggestions.get(this.getIndexOfSuggestionBeingHoveredOver(mouseX, mouseY).get()).getTooltip() != null) {
@@ -173,9 +175,9 @@ public class GuiElementChatSuggestions extends Gui {
         }
     }
 
-    private void renderSingleSuggestionLine(Font fontRenderer, String text, int heightIndex, boolean followParameters) {
+    private void renderSingleSuggestionLine(FontRenderer fontRenderer, String text, int heightIndex, boolean followParameters) {
         int leftMargin = this.xSupplier.get(this.textField, this, this.mc, SUGGESTIONS_FOLLOW_PARAMETERS && followParameters);
-        int stringWidth = fontRenderer.getStringWidth(text);
+        int stringWidth = fontRenderer.stringWidth(text);
 
         leftMargin -= (int) (this.anchor.xPosition * (stringWidth + 2));
 
@@ -184,7 +186,7 @@ public class GuiElementChatSuggestions extends Gui {
         minY += (int) CommandHelper.linearInterpolation(this.anchor.yPosition, heightIndex * 12, -12 - heightIndex * 12);
 
         this.drawRect(leftMargin, minY, stringWidth + leftMargin + 1, minY + 12, Integer.MIN_VALUE);
-        fontRenderer.drawStringWithShadow(text, leftMargin + 1, minY + 2, 0xE0E0E0);
+        FontHelper.render(Tessellator.instance, text, leftMargin + 1, minY + 2).setShadow().setColor(0xE0E0E0).call(fontRenderer);
     }
 
     private List<String> getCommandUsage(int cursor) {
@@ -306,8 +308,8 @@ public class GuiElementChatSuggestions extends Gui {
 
         int largestSuggestion = 0;
         for (Suggestion suggestion : this.suggestions)
-            if (this.fontRenderer.getStringWidth(suggestion.getText()) > largestSuggestion)
-                largestSuggestion = this.fontRenderer.getStringWidth(suggestion.getText());
+            if (this.fontRenderer.stringWidth(suggestion.getText()) > largestSuggestion)
+                largestSuggestion = this.fontRenderer.stringWidth(suggestion.getText());
 
         minX -= (int) (this.anchor.xPosition * (largestSuggestion + 2));
 
@@ -501,7 +503,7 @@ public class GuiElementChatSuggestions extends Gui {
     }
 
     public int getDefaultParameterPosition() {
-        return this.fontRenderer.getStringWidth(this.getMessage().substring(0, Math.min(this.getSuggestionRangeStart(), this.getMessage().length()))) + 2;
+        return this.fontRenderer.stringWidth(this.getMessage().substring(0, Math.min(this.getSuggestionRangeStart(), this.getMessage().length()))) + 2;
     }
 
     public static void drawDottedRect(Gui gui, int minX, int minY, int maxX, int maxY, int argb, int dotSize) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenChat.java b/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenChat.java
index 26d4e249a..9b086d5b7 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenChat.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/chat/ScreenChat.java
@@ -195,22 +195,22 @@ public class ScreenChat extends Screen implements ITextField {
 				emotePickerTextColor = 0xffffffa0;
 			}
 			drawRect(2, height - 14, 14, height - 2, emotePickerButtonColor);
-			drawStringCentered(font, Character.toString('\u263a'), 2 + 6, height - 12, emotePickerTextColor);
+			drawStringCenteredShadow(fontRenderer, Character.toString('\u263a'), 2 + 6, height - 12, emotePickerTextColor);
 
 			drawRect(16, height - 14, width - 2, height - 2, 0x80000000);
 
-			font.drawStringWithShadow(this.suggestionsElement.getSuggestionPreview(), 16 + suggestionsElement.getDefaultParameterPosition(), mc.resolution.getScaledHeightScreenCoords() - 12, 0xFFFFFF);
+			drawStringShadow(fontRenderer, this.suggestionsElement.getSuggestionPreview(), 16 + suggestionsElement.getDefaultParameterPosition(), mc.resolution.getScaledHeightScreenCoords() - 12, 0xFFFFFF);
 			boolean drawCursor = (updateCounter / 6) % 2 == 0;
 			int cursor = editor.getCursor();
-			drawString(font, this.suggestionsElement.colorCodeText(message, true), 18, height - 12, 0xE0E0E0);
+			drawStringShadow(fontRenderer, this.suggestionsElement.colorCodeText(message, true), 18, height - 12, 0xE0E0E0);
 			if (drawCursor)
 			{
-				int width = font.getStringWidth(message);
+				int width = MathHelper.ceil(fontRenderer.stringWidthDouble(message));
 				if (cursor < message.length())
 				{
-					width = font.getStringWidth(message.substring(0, cursor));
+					width = MathHelper.ceil(fontRenderer.stringWidthDouble(message.substring(0, cursor)));
 				}
-				drawString(font, "_", 18 + width, height - 12, 0xE0E0E0);
+				drawStringShadow(fontRenderer, "_", 18 + width, height - 12, 0xE0E0E0);
 			}
 
 			if (showEmotePicker) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenActivator.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenActivator.java
index 4f2ecc8fb..e6e332b24 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenActivator.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenActivator.java
@@ -55,8 +55,8 @@ public class ScreenActivator extends ScreenContainerAbstract {
 
     @Override
     protected void drawGuiContainerForegroundLayer() {
-        font.drawString(I18n.getInstance().translateKey("gui.activator.label.activator"), 60, 6, 0x404040);
-        font.drawString(I18n.getInstance().translateKey("gui.activator.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.activator.label.activator"), 60, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.activator.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainer.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainer.java
index f69be2941..e925eb97d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainer.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainer.java
@@ -23,8 +23,8 @@ public class ScreenContainer extends ScreenContainerAbstract
     @Override
 	protected void drawGuiContainerForegroundLayer()
     {
-        font.drawString(I18n.getInstance().translateKey(lowerChestInventory.getNameTranslationKey()), 8, 6, 0x404040);
-        font.drawString(I18n.getInstance().translateKey(upperChestInventory.getNameTranslationKey()), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey(lowerChestInventory.getNameTranslationKey()), 8, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey(upperChestInventory.getNameTranslationKey()), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
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 6b8c91681..a8cd96504 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
@@ -24,8 +24,8 @@ public class ScreenCrafting extends ScreenContainerAbstract
     @Override
 	protected void drawGuiContainerForegroundLayer()
     {
-        font.drawString(I18n.getInstance().translateKey("gui.crafting.label.crafting"), 28, 6, 0x404040);
-        font.drawString(I18n.getInstance().translateKey("gui.crafting.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.crafting.label.crafting"), 28, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.crafting.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenDispenser.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenDispenser.java
index 8173f109f..1e4b74938 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenDispenser.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenDispenser.java
@@ -17,8 +17,8 @@ public class ScreenDispenser extends ScreenContainerAbstract
     @Override
 	protected void drawGuiContainerForegroundLayer()
     {
-        font.drawString(I18n.getInstance().translateKey("gui.dispenser.label.dispenser"), 60, 6, 0x404040);
-        font.drawString(I18n.getInstance().translateKey("gui.dispenser.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.dispenser.label.dispenser"), 60, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.dispenser.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
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 37e00bc48..e1f9ba18d 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
@@ -402,7 +402,7 @@ public class ScreenFlagEditor
 
     @Override
     protected void drawGuiContainerForegroundLayer() {
-        font.drawString(I18n.getInstance().translateKey("gui.edit_flag.label.inventory"), 8, (ySize - 96) + 2, 0xFF404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.edit_flag.label.inventory"), 8, (ySize - 96) + 2, 0xFF404040);
     }
 
     @Override
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 450a74d81..7b4cbf4c2 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
@@ -22,11 +22,11 @@ public class ScreenFurnace extends ScreenContainerAbstract
     {
         I18n i18n = I18n.getInstance();
         if(furnaceInventory instanceof TileEntityFurnaceBlast) {
-            font.drawString(i18n.translateKey("gui.furnace.blast.label.blast_furnace"), 60, 6, 0x404040);
+            drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.blast.label.blast_furnace"), 60, 6, 0x404040);
         } else {
-            font.drawString(i18n.translateKey("gui.furnace.label.furnace"), 60, 6, 0x404040);
+            drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.furnace"), 60, 6, 0x404040);
         }
-        font.drawString(i18n.translateKey("gui.furnace.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
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 72750dbf2..776ac4e5d 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
@@ -141,7 +141,7 @@ public class ScreenInventory extends ScreenContainerAbstract
     @Override
 	protected void drawGuiContainerForegroundLayer()
     {
-        font.drawString(I18n.getInstance().translateKey("gui.inventory.label.crafting"), 86, 16, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.inventory.label.crafting"), 86, 16, 0x404040);
     }
 
     @Override
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 15040ad0b..a41a7ab13 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
@@ -2,7 +2,6 @@ package net.minecraft.client.gui.container;
 
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.TextFieldElement;
-import net.minecraft.client.gui.keyboard.ScreenKeyboard;
 import net.minecraft.client.input.controller.ControllerInput;
 import net.minecraft.core.InventoryAction;
 import net.minecraft.core.entity.player.Player;
@@ -45,7 +44,7 @@ public class ScreenInventoryCreative extends ScreenInventory implements ITextCha
 		buttons.add(lastPageButton = new ButtonElement(500, 0, 0, 20, 20, "<"));
 		buttons.add(nextPageButton = new ButtonElement(501, 0, 0, 20, 20, ">"));
 		buttons.add(clearSearchButton = new OptionsButtonElement(0, 0, 10, 12, 20, "").setTextures("minecraft:gui/screen/creative/clear", "minecraft:gui/screen/creative/clear_highlighted", null));
-		searchField = new TextFieldElement(this, font, 0, 0, 96, 18, container.searchText, I18n.getInstance().translateKey("gui.inventory.creative.label.search"));
+		searchField = new TextFieldElement(this, fontRenderer, 0, 0, 96, 18, container.searchText, I18n.getInstance().translateKey("gui.inventory.creative.label.search"));
 		searchField.drawBackground =false;
 		searchField.setMaxStringLength(14);
 		searchField.setTextChangeListener(this);
@@ -168,7 +167,7 @@ public class ScreenInventoryCreative extends ScreenInventory implements ITextCha
 	protected void drawGuiContainerForegroundLayer()
     {
     	super.drawGuiContainerForegroundLayer();
-    	drawStringCenteredNoShadow(font, pageString, 238, 146, 0x404040);
+    	drawStringCenteredNoShadow(fontRenderer, pageString, 238, 146, 0x404040);
     }
 	
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenTrommel.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenTrommel.java
index e769aeb28..3319ff80d 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenTrommel.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenTrommel.java
@@ -19,8 +19,8 @@ public class ScreenTrommel extends ScreenContainerAbstract
     @Override
 	protected void drawGuiContainerForegroundLayer()
     {
-        font.drawString(I18n.getInstance().translateKey("gui.trommel.label.trommel"), 60, 6, 0x404040);
-        font.drawString(I18n.getInstance().translateKey("gui.trommel.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.trommel.label.trommel"), 60, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, I18n.getInstance().translateKey("gui.trommel.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/createworld/ButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/createworld/ButtonComponent.java
index b5de2a188..cb571c2f0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/createworld/ButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/createworld/ButtonComponent.java
@@ -3,7 +3,7 @@ package net.minecraft.client.gui.createworld;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.paged.PageComponent;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
@@ -42,16 +42,15 @@ public abstract class ButtonComponent
     @Override
     public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY)
     {
-        Font fr = mc.font;
         String translated = I18n.getInstance().translateKey(translationKey);
         int textColor = 0xFFFFFFFF;
         if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= getHeight() - COMPONENT_SPACING) {
             textColor = 0xFFFFFFA0;
         }
-        fr.drawStringWithShadow(translated, x, y + (getHeight() / 2) - 4, textColor);
+        FontHelper.render(Tessellator.instance, translated, x, y + (getHeight() / 2) - 4).setShadow().setColor(textColor).call(mc.font);
         resetButton.enabled = !isDefault();
         renderButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, BUTTON_WIDTH, 20, relativeMouseX, relativeMouseY);
-        int stringWidth = fr.getStringWidth(translated);
+        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);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/createworld/TextFieldComponent.java b/game/client/src/main/java/net/minecraft/client/gui/createworld/TextFieldComponent.java
index c4c869d85..f0318cdd6 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/createworld/TextFieldComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/createworld/TextFieldComponent.java
@@ -4,9 +4,8 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.TextFieldElement;
 import net.minecraft.client.gui.paged.CallbackComponent;
 import net.minecraft.client.gui.paged.OnValueChangedCallback;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.client.render.window.CursorShape;
 import net.minecraft.core.lang.I18n;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -49,14 +48,13 @@ public class TextFieldComponent
     @Override
     public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY)
     {
-        Font fr = mc.font;
         String translated = I18n.getInstance().translateKey(translationKey);
         int textColor = 0xFFFFFFFF;
         if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= getHeight() - COMPONENT_SPACING) {
             textColor = 0xFFFFFFA0;
         }
-        fr.drawStringWithShadow(translated, x, y + (getHeight() / 2) - 4, textColor);
-        int stringWidth = fr.getStringWidth(translated);
+        FontHelper.render(Tessellator.instance, translated, x, y + (getHeight() / 2) - 4).setShadow().setColor(textColor).call(mc.font);
+        int stringWidth = mc.font.stringWidth(translated);
         int lineMaxX = x + width - BUTTON_WIDTH - 8;
         drawRect(x + stringWidth + 8, y + getHeight() / 2, lineMaxX, y + getHeight() / 2 + 1, 0x5F7F7F7F);
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/GuidebookPage.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/GuidebookPage.java
index c46fc54f6..439660536 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/GuidebookPage.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/GuidebookPage.java
@@ -1,8 +1,8 @@
 package net.minecraft.client.gui.guidebook;
 
 import net.minecraft.client.gui.Gui;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.util.helper.Color;
 import org.lwjgl.opengl.GL11;
@@ -27,18 +27,18 @@ public abstract class GuidebookPage
         drawTexturedModalRect(x, y, 0, 0, width, height);
     }
 
-    protected abstract void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks);
+    protected abstract void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks);
 
     public boolean drawHeaders() {
         return true;
     }
 
-    public void render(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    public void render(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         renderBackground(re, x, y);
-        renderForeground(re, fr, x, y, mouseX, mouseY, partialTicks);
+        renderForeground(re, sr, x, y, mouseX, mouseY, partialTicks);
     }
 
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) { };
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) { };
 
     public void onMouseDown(int x, int y, int mouseX, int mouseY, int button) { }
 
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 134d3721e..3ca8638d1 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
@@ -7,11 +7,11 @@ import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.client.gui.guidebook.search.GuidebookPageSearch;
 import net.minecraft.client.gui.guidebook.search.GuidebookSectionSearch;
 import net.minecraft.client.input.controller.ControllerInput;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.OpenGLHelper;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.entity.EntityRendererItem;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.item.ItemStack;
@@ -454,13 +454,13 @@ public class ScreenGuidebook
 
         //find a way how to display the total number of pages properly maybe
         if (leftPage != null && leftPage.drawHeaders()) {
-            drawStringNoShadow(font, String.valueOf(guidebookPageManager.getPageIndex(leftPage)) /*+ "/" + guidebookPageManager.getNumPages()*/, left + 12, bottom - 20, 0xFF000000);
-            drawStringCenteredNoShadow(font, I18n.getInstance().translateKey(guidebookPageManager.getLeftPage().getSection().getTranslationKey()), left + 158 / 2, bottom - 20, 0xFF808080);
+            drawStringNoShadow(fontRenderer, String.valueOf(guidebookPageManager.getPageIndex(leftPage)) /*+ "/" + guidebookPageManager.getNumPages()*/, left + 12, bottom - 20, 0xFF000000);
+            drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey(guidebookPageManager.getLeftPage().getSection().getTranslationKey()), left + 158 / 2, bottom - 20, 0xFF808080);
         }
         if (rightPage != null && rightPage.drawHeaders()) {
             String str = String.valueOf(guidebookPageManager.getPageIndex(rightPage)); /*+ "/" + guidebookPageManager.getNumPages();*/
-            drawStringNoShadow(font, str, right - 12 - font.getStringWidth(str), bottom - 20, 0xFF000000);
-            drawStringCenteredNoShadow(font, I18n.getInstance().translateKey(guidebookPageManager.getRightPage().getSection().getTranslationKey()), right - 158 / 2, bottom - 20, 0xFF808080);
+            drawStringNoShadow(fontRenderer, str, right - 12 - MathHelper.ceil(fontRenderer.stringWidthDouble(str)), bottom - 20, 0xFF000000);
+            drawStringCenteredNoShadow(fontRenderer, I18n.getInstance().translateKey(guidebookPageManager.getRightPage().getSection().getTranslationKey()), right - 158 / 2, bottom - 20, 0xFF808080);
         }
     }
 
@@ -528,7 +528,7 @@ public class ScreenGuidebook
             this.active = active;
         }
 
-        public void render(TextureManager re, Font fr, int mouseX, int mouseY) {
+        public void render(TextureManager re, FontRenderer sr, int mouseX, int mouseY) {
             boolean mouseOver = mouseOver(mouseX, mouseY);
 
             re.bindTexture(re.loadTexture("/assets/minecraft/textures/gui/container/guidebook/guidebook.png"));
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/cover/GuidebookPageCover.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/cover/GuidebookPageCover.java
index 126b327fc..3fffd566c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/cover/GuidebookPageCover.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/cover/GuidebookPageCover.java
@@ -2,8 +2,8 @@ package net.minecraft.client.gui.guidebook.cover;
 
 import net.minecraft.client.gui.guidebook.GuidebookPage;
 import net.minecraft.client.gui.guidebook.GuidebookSection;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.Global;
 
 public class GuidebookPageCover
@@ -24,8 +24,8 @@ public class GuidebookPageCover
     }
 
     @Override
-    public void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        drawStringCenteredNoShadow(fr, Global.VERSION, x + 84, y + 151, (getSection().getForegroundColor() & 0xFCFCFC) >> 2);
-        drawStringCenteredNoShadow(fr, Global.VERSION, x + 84, y + 150, getSection().getForegroundColor());
+    public void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        drawStringCenteredNoShadow(sr, Global.VERSION, x + 84, y + 151, (getSection().getForegroundColor() & 0xFCFCFC) >> 2);
+        drawStringCenteredNoShadow(sr, Global.VERSION, x + 84, y + 150, getSection().getForegroundColor());
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/RecipePageCrafting.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/RecipePageCrafting.java
index 5e18d1e48..dc98a41f3 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/RecipePageCrafting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/crafting/RecipePageCrafting.java
@@ -19,8 +19,8 @@ import net.minecraft.client.gui.guidebook.crafting.displays.DisplayAdapterShapel
 import net.minecraft.client.gui.guidebook.crafting.displays.DisplayAdapterTool;
 import net.minecraft.client.gui.guidebook.crafting.displays.DisplayAdapterUndye;
 import net.minecraft.client.gui.guidebook.search.GuidebookPageSearch;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
 import net.minecraft.core.data.registry.recipe.SearchQuery;
@@ -112,9 +112,9 @@ public class RecipePageCrafting
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         if(recipes.isEmpty()){
-            drawStringCenteredNoShadow(fr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes"), x+width/2,y+height/2,0xFF808080);
+            drawStringCenteredNoShadow(sr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes"), x+width/2,y+height/2,0xFF808080);
         }
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
@@ -170,8 +170,8 @@ public class RecipePageCrafting
     }
 
     @Override
-    public void render(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.render(re, fr, x, y, mouseX, mouseY, partialTicks);
+    public void render(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.render(re, sr, x, y, mouseX, mouseY, partialTicks);
 
     }
 
@@ -187,8 +187,8 @@ public class RecipePageCrafting
     }
 
     @Override
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.renderOverlay(re, fr, x, y, mouseX, mouseY, partialTicks);
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.renderOverlay(re, sr, x, y, mouseX, mouseY, partialTicks);
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
             if(getIsMouseOverSlot(slot,x,y,mouseX,mouseY)) mouseOverSlot = slot;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/index/GuidebookPageIndex.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/index/GuidebookPageIndex.java
index fd799c999..53d2fcf23 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/index/GuidebookPageIndex.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/index/GuidebookPageIndex.java
@@ -4,9 +4,10 @@ import net.minecraft.client.gui.guidebook.GuidebookPageManager;
 import net.minecraft.client.gui.guidebook.ScreenGuidebook;
 import net.minecraft.client.gui.guidebook.GuidebookPage;
 import net.minecraft.client.gui.guidebook.GuidebookSection;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.opengl.GL11;
 
 import java.util.List;
@@ -27,7 +28,7 @@ public class GuidebookPageIndex
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         int yOffset = 10;
         for (int i = startIndex; i < startIndex + LINES_PER_PAGE && i < lines.size() / 2; i++) {
             int j = i - startIndex;
@@ -41,21 +42,21 @@ public class GuidebookPageIndex
 
             String lineStr = "";
             String pageStr = String.valueOf(pageNumber);
-            int pageStrWidth = fr.getStringWidth(pageStr);
+            int pageStrWidth = MathHelper.ceil(sr.stringWidthDouble(pageStr));
             int lineXMod = 0;
             if (line instanceof GuidebookSection) {
                 GuidebookSection section = (GuidebookSection) line;
                 lineStr = I18n.getInstance().translateKey(section.getTranslationKey());
-                drawStringNoShadow(fr, lineStr, x + 10, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x404040);
+                drawStringNoShadow(sr, lineStr, x + 10, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x404040);
             } else if (line instanceof GuidebookSection.Index) {
                 GuidebookSection.Index index = (GuidebookSection.Index) line;
                 lineStr = index.getName();
                 lineXMod = 16;
-                drawStringNoShadow(fr, lineStr, x + 10 + lineXMod, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x606060);
+                drawStringNoShadow(sr, lineStr, x + 10 + lineXMod, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x606060);
             }
-            drawStringNoShadow(fr, pageStr, x + 158 - 10 - pageStrWidth, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x404040);
+            drawStringNoShadow(sr, pageStr, x + 158 - 10 - pageStrWidth, y + yOffset + 10 + j * 12, mouseOver ? 0xFFFFFF : 0x404040);
 
-            int lineStrWidth = fr.getStringWidth(lineStr);
+            int lineStrWidth = MathHelper.ceil(sr.stringWidthDouble(lineStr));
 
             GL11.glDisable(GL11.GL_TEXTURE_2D);
             drawRect(x + 10 + lineStrWidth + 4 + lineXMod, y + yOffset + 10 + j * 12 + 6, x + 158 - 10 - pageStrWidth - 4, y + yOffset + 10 + j * 12 + 7, 0xFFA0A0A0);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/GuidebookPageMob.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/GuidebookPageMob.java
index 1e8f99785..2662f8106 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/GuidebookPageMob.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/mobs/GuidebookPageMob.java
@@ -7,6 +7,7 @@ import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.client.gui.guidebook.GuidebookPage;
 import net.minecraft.client.gui.guidebook.GuidebookSection;
 import net.minecraft.client.render.*;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.achievement.stat.StatList;
@@ -18,6 +19,7 @@ import net.minecraft.core.lang.I18n;
 import net.minecraft.core.player.gamemode.Gamemode;
 import net.minecraft.core.player.inventory.slot.Slot;
 import net.minecraft.client.gui.guidebook.SlotGuidebook;
+import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -69,12 +71,12 @@ public class GuidebookPageMob
         discovered = mc.statsCounter.readStat(StatList.mobEncounterStats.get(EntityDispatcher.idForClass(mobClass))) > 0;
     }
 
-    private static String[] createDescLines(Font fr, String languageKey) {
+    private static String[] createDescLines(FontRenderer sr, String languageKey) {
         String[] words = I18n.getInstance().translateKey(languageKey).split(" ");
         List<String> lines = new ArrayList<>();
         StringBuilder line = new StringBuilder();
         for (String word : words) {
-            if (fr.getStringWidth(line + " " + word) > 142) {
+            if (sr.stringWidthDouble(line + " " + word) > 142) {
                 lines.add(line.toString());
                 line = new StringBuilder();
             }
@@ -104,7 +106,7 @@ public class GuidebookPageMob
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         discovered = mc.statsCounter.readStat(StatList.mobEncounterStats.get(EntityDispatcher.idForClass(mobClass))) > 0;
         if (mc.thePlayer.getGamemode() == Gamemode.creative || !mc.gameSettings.hideUndiscoveredItems.value) discovered = true;
 
@@ -114,9 +116,9 @@ public class GuidebookPageMob
 
             String[] lines;
             if (!discovered) {
-                lines = createDescLines(fr, "guidebook.section.mob.undiscovered");
+                lines = createDescLines(sr, "guidebook.section.mob.undiscovered");
             } else {
-                lines = createDescLines(fr, mobInfo.getDescriptionTranslationKey());
+                lines = createDescLines(sr, mobInfo.getDescriptionTranslationKey());
             }
 
             // Display name
@@ -125,24 +127,24 @@ public class GuidebookPageMob
             if (!discovered) {
                 name = new String(new char[name.length()]).replace("\0", "?");
             }
-            drawStringNoShadow(fr, name, x + 66, y + 8, 0x000000);
+            drawStringNoShadow(sr, name, x + 66, y + 8, 0x000000);
 
             if (discovered) {
                 // Display health
                 if (mobInfo.getHealth() > 0) {
                     if(mobInfo.getHealth() > 40){
                         yOffset += 12;
-                        drawStringNoShadow(fr, i18n.translateKey("guidebook.section.mob.health"), x + 66, yOffset, 0x505050);
+                        drawStringNoShadow(sr, i18n.translateKey("guidebook.section.mob.health"), x + 66, yOffset, 0x505050);
                         yOffset += 6;
                         GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset color
                         yOffset += 4;
                         drawGuiIcon(x + 66, yOffset, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/container"));
                         drawGuiIcon(x + 66, yOffset, 9, 9, TextureRegistry.getTexture("minecraft:gui/hud/heart/full"));
-                        drawStringNoShadow(fr, "x "+mobInfo.getHealth()/2, x + 66 + 12, yOffset, 0x505050);
+                        drawStringNoShadow(sr, "x "+mobInfo.getHealth()/2, x + 66 + 12, yOffset, 0x505050);
 
                     } else {
                         yOffset += 12;
-                        drawStringNoShadow(fr, i18n.translateKey("guidebook.section.mob.health"), x + 66, yOffset, 0x505050);
+                        drawStringNoShadow(sr, i18n.translateKey("guidebook.section.mob.health"), x + 66, yOffset, 0x505050);
                         yOffset += 6;
                         GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset color
                         for (int i = 0; i < mobInfo.getHealth() / 2; i++) {
@@ -162,14 +164,14 @@ public class GuidebookPageMob
                 // Display score
                 if (mobInfo.getScore() > 0) {
                     yOffset += 11;
-                    drawStringNoShadow(fr, i18n.translateKeyAndFormat("guidebook.section.mob.score", mobInfo.getScore()), x + 66, yOffset, 0x505050);
+                    drawStringNoShadow(sr, i18n.translateKeyAndFormat("guidebook.section.mob.score", mobInfo.getScore()), x + 66, yOffset, 0x505050);
                 }
             }
 
             // Display description
             yOffset = y + 84;
             for (String descLine : lines) {
-                drawStringNoShadow(fr, descLine, x + 8, yOffset, 0x505050);
+                drawStringNoShadow(sr, descLine, x + 8, yOffset, 0x505050);
                 yOffset += 10;
             }
 
@@ -177,7 +179,7 @@ public class GuidebookPageMob
                 // Display drops
                 if (mobInfo.getDrops() != null && mobInfo.getDrops().length > 0) {
                     yOffset += 4;
-                    drawStringNoShadow(fr, i18n.translateKey("guidebook.section.mob.drops"), x + 8, yOffset, 0x000000);
+                    drawStringNoShadow(sr, i18n.translateKey("guidebook.section.mob.drops"), x + 8, yOffset, 0x000000);
                     yOffset += 12;
                     for (int i = 0; i < mobInfo.getDrops().length; i++) {
                         SlotGuidebook slot = slots.get(i);
@@ -192,14 +194,14 @@ public class GuidebookPageMob
                         GL11.glPopMatrix();
                         if (slot.getIsDiscovered(mc.thePlayer)) {
                             String amountString = drop.getMinAmount() == drop.getMaxAmount() ? String.valueOf(drop.getMinAmount()) : drop.getMinAmount() + "-" + drop.getMaxAmount();
-                            int width = fr.getStringWidth(amountString);
-                            drawString(fr, amountString, x + 8 + (i % 7) * 21 + 16 - width + 1, yOffset + 10 + (i / 7) * 20, 0xFFFFFFFF);
+                            int width = MathHelper.ceil(sr.stringWidthDouble(amountString));
+                            drawStringShadow(sr, amountString, x + 8 + (i % 7) * 21 + 16 - width + 1, yOffset + 10 + (i / 7) * 20, 0xFFFFFFFF);
                         }
                     }
                 }
             }
         } else {
-            drawStringCenteredNoShadow(fr,"No results :(" ,x+width/2,y+height/2,0xFF808080);
+            drawStringCenteredNoShadow(sr,"No results :(" ,x+width/2,y+height/2,0xFF808080);
         }
 
         renderMob(x, y, mouseX, mouseY, partialTicks);
@@ -268,8 +270,8 @@ public class GuidebookPageMob
     }
 
     @Override
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.renderOverlay(re, fr, x, y, mouseX, mouseY, partialTicks);
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.renderOverlay(re, sr, x, y, mouseX, mouseY, partialTicks);
         if (slots == null) return;
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/search/GuidebookPageSearch.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/search/GuidebookPageSearch.java
index bfc866176..815af1884 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/search/GuidebookPageSearch.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/search/GuidebookPageSearch.java
@@ -4,8 +4,8 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
 import net.minecraft.client.gui.TextFieldElement;
 import net.minecraft.client.gui.guidebook.*;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.data.registry.recipe.SearchQuery;
 import net.minecraft.core.lang.I18n;
 
@@ -20,7 +20,7 @@ public class GuidebookPageSearch extends GuidebookPage {
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         searchField.xPosition = x + width/2 - searchField.width/2 - 10;
         searchField.yPosition = y + height/2 - searchField.height/2 - 70;
         searchClearButton.xPosition = searchField.xPosition + searchField.width + 5;
@@ -38,19 +38,19 @@ public class GuidebookPageSearch extends GuidebookPage {
 
         I18n tr = I18n.getInstance();
 
-        drawStringCenteredNoShadow(fr,tr.translateKeyAndFormat("guidebook.section.search.result.found", results),x+width/2,y+10, 0xFF404040);
+        drawStringCenteredNoShadow(sr,tr.translateKeyAndFormat("guidebook.section.search.result.found", results),x+width/2,y+10, 0xFF404040);
 
         int offset = y+70;
-        drawStringCenteredNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.title"),x+width/2,offset, 0xFF404040);
-        drawStringNoShadow(fr, tr.translateKey("guidebook.section.search.info.modifiers.1"),x+10,offset+=15, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.2"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.3"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.4"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.5"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.6"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.7"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.8"),x+10,offset+=10, 0xFF404040);
-        drawStringNoShadow(fr,tr.translateKey("guidebook.section.search.info.modifiers.9"),x+10,offset+=15, 0xFF404040);
+        drawStringCenteredNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.title"),x+width/2,offset, 0xFF404040);
+        drawStringNoShadow(sr, tr.translateKey("guidebook.section.search.info.modifiers.1"),x+10,offset+=15, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.2"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.3"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.4"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.5"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.6"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.7"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.8"),x+10,offset+=10, 0xFF404040);
+        drawStringNoShadow(sr,tr.translateKey("guidebook.section.search.info.modifiers.9"),x+10,offset+=15, 0xFF404040);
     }
 
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
index 53acf5caa..07271ee38 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
@@ -9,8 +9,8 @@ import net.minecraft.client.gui.guidebook.GuidebookSection;
 import net.minecraft.client.gui.guidebook.GuidebookSections;
 import net.minecraft.client.gui.guidebook.RecipePage;
 import net.minecraft.client.gui.guidebook.search.GuidebookPageSearch;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.SearchQuery;
@@ -70,9 +70,9 @@ public class RecipePageBlastSmelting
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         if(recipes.isEmpty()){
-            drawStringCenteredNoShadow(fr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
+            drawStringCenteredNoShadow(sr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
         }
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
@@ -125,8 +125,8 @@ public class RecipePageBlastSmelting
     }
 
     @Override
-    public void render(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.render(re, fr, x, y, mouseX, mouseY, partialTicks);
+    public void render(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.render(re, sr, x, y, mouseX, mouseY, partialTicks);
 
     }
 
@@ -142,8 +142,8 @@ public class RecipePageBlastSmelting
     }
 
     @Override
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.renderOverlay(re, fr, x, y, mouseX, mouseY, partialTicks);
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.renderOverlay(re, sr, x, y, mouseX, mouseY, partialTicks);
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
             if(getIsMouseOverSlot(slot,x,y,mouseX,mouseY)) mouseOverSlot = slot;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageSmelting.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageSmelting.java
index 87143126e..d90e32c14 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageSmelting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageSmelting.java
@@ -9,8 +9,8 @@ import net.minecraft.client.gui.guidebook.GuidebookSection;
 import net.minecraft.client.gui.guidebook.GuidebookSections;
 import net.minecraft.client.gui.guidebook.RecipePage;
 import net.minecraft.client.gui.guidebook.search.GuidebookPageSearch;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.achievement.Achievements;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.SearchQuery;
@@ -70,9 +70,9 @@ public class RecipePageSmelting
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         if(recipes.isEmpty()){
-            drawStringCenteredNoShadow(fr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
+            drawStringCenteredNoShadow(sr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
         }
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
@@ -125,8 +125,8 @@ public class RecipePageSmelting
     }
 
     @Override
-    public void render(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.render(re, fr, x, y, mouseX, mouseY, partialTicks);
+    public void render(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.render(re, sr, x, y, mouseX, mouseY, partialTicks);
 
     }
 
@@ -142,8 +142,8 @@ public class RecipePageSmelting
     }
 
     @Override
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.renderOverlay(re, fr, x, y, mouseX, mouseY, partialTicks);
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.renderOverlay(re, sr, x, y, mouseX, mouseY, partialTicks);
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
             if(getIsMouseOverSlot(slot,x,y,mouseX,mouseY)) mouseOverSlot = slot;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/trommeling/RecipePageTrommel.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/trommeling/RecipePageTrommel.java
index 2175f4d93..7cdf01baa 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/trommeling/RecipePageTrommel.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/trommeling/RecipePageTrommel.java
@@ -9,8 +9,8 @@ import net.minecraft.client.gui.guidebook.GuidebookSection;
 import net.minecraft.client.gui.guidebook.GuidebookSections;
 import net.minecraft.client.gui.guidebook.RecipePage;
 import net.minecraft.client.gui.guidebook.search.GuidebookPageSearch;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.WeightedRandomBag;
 import net.minecraft.core.WeightedRandomLootObject;
 import net.minecraft.core.achievement.Achievements;
@@ -119,9 +119,9 @@ public class RecipePageTrommel
     }
 
     @Override
-    protected void renderForeground(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+    protected void renderForeground(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
         if(recipes.isEmpty()){
-            drawStringCenteredNoShadow(fr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
+            drawStringCenteredNoShadow(sr, I18n.getInstance().translateKey("guidebook.section.search.error.no_recipes") ,x+width/2,y+height/2,0xFF808080);
         }
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
@@ -174,8 +174,8 @@ public class RecipePageTrommel
     }
 
     @Override
-    public void render(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.render(re, fr, x, y, mouseX, mouseY, partialTicks);
+    public void render(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.render(re, sr, x, y, mouseX, mouseY, partialTicks);
 
     }
 
@@ -191,8 +191,8 @@ public class RecipePageTrommel
     }
 
     @Override
-    protected void renderOverlay(TextureManager re, Font fr, int x, int y, int mouseX, int mouseY, float partialTicks) {
-        super.renderOverlay(re, fr, x, y, mouseX, mouseY, partialTicks);
+    protected void renderOverlay(TextureManager re, FontRenderer sr, int x, int y, int mouseX, int mouseY, float partialTicks) {
+        super.renderOverlay(re, sr, x, y, mouseX, mouseY, partialTicks);
         SlotGuidebook mouseOverSlot = null;
         for (SlotGuidebook slot : slots) {
             if(getIsMouseOverSlot(slot,x,y,mouseX,mouseY)) mouseOverSlot = slot;
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
index 4a308f6da..859aa3078 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngame.java
@@ -16,20 +16,20 @@ import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.HeldItemTooltipElement;
 import net.minecraft.client.gui.ScreenPhotoMode;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.core.block.BlockLogicPortal;
 import net.minecraft.core.enums.ChatVisibility;
 import net.minecraft.core.enums.HumanArmorShape;
-import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.util.helper.Direction;
+import org.jetbrains.annotations.NotNull;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.hud.component.HudComponent;
 import net.minecraft.client.gui.hud.component.HudComponents;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.dynamictexture.DynamicTexture;
-import net.minecraft.client.render.entity.EntityRendererItem;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.render.terrain.RenderList;
 import net.minecraft.client.render.terrain.RenderRegion;
@@ -61,11 +61,11 @@ import org.slf4j.Logger;
 public class HudIngame extends Gui
 {
     public static final float DEBUG_SCALE = 1f;
+    public static final int MAX_CHAT_WIDTH = 320;
     private static final Logger LOGGER = LogUtils.getLogger();
     public static final Direction[] directions = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
 
-    public static EntityRendererItem itemRenderer = new EntityRendererItem();
-    private final List<ChatLine> chatMessageList = new ArrayList<>();
+    private final @NotNull List<@NotNull ChatLine> chatMessageList = new ArrayList<>();
     protected Minecraft mc;
     public int updateCounter = 0;
     private String recordPlaying = "";
@@ -73,7 +73,7 @@ public class HudIngame extends Gui
     private boolean colorString = false;
     public float damageGuiPartialTime;
     float prevVignetteBrightness = 1.0f;
-    protected Font font;
+    protected FontRenderer fontRenderer;
     public int chatScroll = 0;
 
     public final HeldItemTooltipElement heldItemTooltipElement;
@@ -81,7 +81,7 @@ public class HudIngame extends Gui
     public HudIngame(Minecraft minecraft)
     {
         this.mc = minecraft;
-        this.font = mc.font;
+        this.fontRenderer = this.mc.font;
         this.heldItemTooltipElement = new HeldItemTooltipElement(mc);
     }
 
@@ -93,7 +93,6 @@ public class HudIngame extends Gui
         int width = mc.resolution.getScaledWidthScreenCoords();
         int height = mc.resolution.getScaledHeightScreenCoords();
         int sp = (int) ((mc.gameSettings.screenPadding.value * height) / 8);
-        Font font = mc.font;
         mc.worldRenderer.setupScaledResolution();
 
         GL11.glEnable(3042 /* GL_BLEND */);
@@ -435,12 +434,12 @@ public class HudIngame extends Gui
                     } else {
                         color = 0xFFFFFF;
                     }
-                    drawString(font, "Better than Adventure! ", tsp, tsp + lineHeight * line, color);
-                    drawString(font, Global.VERSION, tsp + font.getStringWidth("Better than Adventure! "), tsp + lineHeight * line++, 0xffffff);
+                    drawStringShadow(fontRenderer, "Better than Adventure! ", tsp, tsp + lineHeight * line, color);
+                    drawStringShadow(fontRenderer, Global.VERSION, FontHelper.getLastEndingX(), tsp + lineHeight * line++, 0xffffff);
                 }
                 if (mc.gameSettings.fpsInOverlay.value)
                 {
-                    drawString(font, mc.debugFPS, tsp, tsp + lineHeight * line++, 0xffffff);
+                    drawStringShadow(fontRenderer, mc.debugFPS, tsp, tsp + lineHeight * line++, 0xffffff);
                 }
                 if (compass)
                 {
@@ -448,24 +447,24 @@ public class HudIngame extends Gui
                     {
                         if (mc.gameSettings.overlayMode.value == 0)
                         {
-                            drawString(font, "x: " + floor10(mc.thePlayer.x) + " y: " + floor10(mc.thePlayer.y) + " z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0xffffff);
+                            drawStringShadow(fontRenderer, "x: " + floor10(mc.thePlayer.x) + " y: " + floor10(mc.thePlayer.y) + " z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0xffffff);
                         }
                         if (mc.gameSettings.overlayMode.value == 1)
                         {
-                            drawString(font, "x: " + floor10(mc.thePlayer.x), tsp, tsp + lineHeight * line++, 0xffffff);
-                            drawString(font, "y: " + floor10(mc.thePlayer.y), tsp, tsp + lineHeight * line++, 0xffffff);
-                            drawString(font, "z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0xffffff);
+                            drawStringShadow(fontRenderer, "x: " + floor10(mc.thePlayer.x), tsp, tsp + lineHeight * line++, 0xffffff);
+                            drawStringShadow(fontRenderer, "y: " + floor10(mc.thePlayer.y), tsp, tsp + lineHeight * line++, 0xffffff);
+                            drawStringShadow(fontRenderer, "z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0xffffff);
                         }
                         if (mc.gameSettings.overlayMode.value == 2)
                         {
-                            drawString(font, "x: " + floor10(mc.thePlayer.x), tsp, tsp + lineHeight * line++, 0xff8080);
-                            drawString(font, "y: " + floor10(mc.thePlayer.y), tsp, tsp + lineHeight * line++, 0x80ff80);
-                            drawString(font, "z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0x8080ff);
+                            drawStringShadow(fontRenderer, "x: " + floor10(mc.thePlayer.x), tsp, tsp + lineHeight * line++, 0xff8080);
+                            drawStringShadow(fontRenderer, "y: " + floor10(mc.thePlayer.y), tsp, tsp + lineHeight * line++, 0x80ff80);
+                            drawStringShadow(fontRenderer, "z: " + floor10(mc.thePlayer.z), tsp, tsp + lineHeight * line++, 0x8080ff);
                         }
                     }
                     if (mc.gameSettings.overlayShowDirection.value)
                     {
-                        drawString(font, I18n.getInstance().translateKey(getFacingDirection(mc.thePlayer).getTranslationKey()), tsp, tsp + lineHeight * line++, 0xffffff);
+                        drawStringShadow(fontRenderer, I18n.getInstance().translateKey(getFacingDirection(mc.thePlayer).getTranslationKey()), tsp, tsp + lineHeight * line++, 0xffffff);
                     }
                 }
                 if (clock)
@@ -474,12 +473,12 @@ public class HudIngame extends Gui
                     {
                         if (mc.gameSettings.overlayMode.value == 0)
                         {
-                            this.drawString(font, String.format("%s %s %d", getTimeString(), I18n.getInstance().translateKey("unit.day"),mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
+                            this.drawStringShadow(fontRenderer, String.format("%s %s %d", getTimeString(), I18n.getInstance().translateKey("unit.day"),mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
                         }
                         if (mc.gameSettings.overlayMode.value > 0)
                         {
-                            this.drawString(font, getTimeString(), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
-                            this.drawString(font, String.format("%s %d", I18n.getInstance().translateKey("unit.day"),mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
+                            this.drawStringShadow(fontRenderer, getTimeString(), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
+                            this.drawStringShadow(fontRenderer, String.format("%s %d", I18n.getInstance().translateKey("unit.day"),mc.currentWorld.getWorldTime() / Global.DAY_LENGTH_TICKS), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xffff80 : 0xffffff);
                         }
                     }
                 }
@@ -490,7 +489,7 @@ public class HudIngame extends Gui
                         Season season = mc.currentWorld.getSeasonManager().getCurrentSeason();
                         if (season != null)
                         {
-                            this.drawString(font, season.getTranslatedName(), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0x80ffff : 0xffffff);
+                            this.drawStringShadow(fontRenderer, season.getTranslatedName(), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0x80ffff : 0xffffff);
                         }
                     }
                     if (mc.gameSettings.overlayShowWeather.value)
@@ -498,7 +497,7 @@ public class HudIngame extends Gui
                         Weather weather = mc.currentWorld.getCurrentWeather();
                         if (weather != null && weather != mc.currentWorld.worldType.getDefaultWeather())
                         {
-                            this.drawString(font, stringtranslate.translateKey(weather.getNameLanguageKey()), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xff80ff : 0xffffff);
+                            this.drawStringShadow(fontRenderer, stringtranslate.translateKey(weather.getNameLanguageKey()), tsp, tsp + lineHeight * line++, mc.gameSettings.overlayMode.value == 2 ? 0xff80ff : 0xffffff);
                         }
                     }
 					if(mc.gameSettings.overlayShowBiome.value)
@@ -507,7 +506,7 @@ public class HudIngame extends Gui
 						int blockY = MathHelper.floor(mc.thePlayer.y);
 						int blockZ = MathHelper.floor(mc.thePlayer.z);
 						String key = mc.currentWorld.getBlockBiome(blockX, blockY, blockZ).translationKey;
-						drawString(font, stringtranslate.translateKey(key), tsp, tsp + lineHeight * line++, 0xffffff);
+						drawStringShadow(fontRenderer, stringtranslate.translateKey(key), tsp, tsp + lineHeight * line++, 0xffffff);
 					}
                 }
             }
@@ -535,7 +534,7 @@ public class HudIngame extends Gui
 
                         glDisable(GL_BLEND);
                         glDisable(GL_LIGHTING);
-                        font.drawStringWithShadow(String.valueOf((stack.getMaxDamage() - stack.getMetadata()) + 1), x + 20, y + 4, i1);
+                        drawStringShadow(this.fontRenderer, String.valueOf((stack.getMaxDamage() - stack.getMetadata()) + 1), x + 20, y + 4, i1);
                     }
                 }
             }
@@ -561,7 +560,7 @@ public class HudIngame extends Gui
                     
                     final int color = Color.HSBtoRGB(durability/3F, 1f, 1f);
                     int remainingDurability = (heldItemStack.getMaxDamage() - heldItemStack.getMetadata()) + 1;
-                    font.drawStringWithShadow("" + remainingDurability, x + 18, y + 4, color);
+                    drawStringShadow(this.fontRenderer, "" + remainingDurability, x + 18, y + 4, color);
                 }
                 else
                 {
@@ -580,7 +579,7 @@ public class HudIngame extends Gui
 
                     if (renderItem)
                     {
-                        font.drawStringWithShadow("" + itemCount, x + 18, y + 4, 0xffffff);
+                        drawStringShadow(this.fontRenderer, "" + itemCount, x + 18, y + 4, 0xffffff);
                     }
                 }
 
@@ -661,35 +660,35 @@ public class HudIngame extends Gui
 
     private final int debugLineHeight = 10;
 
-    private void drawDebugScreenLine(String string, boolean right, int line, int offset)
+    private void drawDebugScreenLine(final CharSequence string, final boolean right, final int line, final int offset)
     {
-        int width = font.getStringWidth(string);
+        int width = MathHelper.ceil(this.fontRenderer.stringWidthDouble(string));
         int height = debugLineHeight;
         int x = right ? (int) ((mc.resolution.getScaledWidthScreenCoords() / DEBUG_SCALE) - width - 2) : 2;
         int y = 3 + line * debugLineHeight + offset;
 
         glDisable(GL_TEXTURE_2D);
         glColor4d(0.2, 0.2, 0.2, 0.6);
-        Tessellator tessellator = Tessellator.instance;
+        final Tessellator t = Tessellator.instance;
 
-        tessellator.startDrawingQuads();
-        tessellator.drawRectangle(x - 1, y - 1, width + 2, height);
-        tessellator.draw();
+        t.startDrawingQuads();
+        t.drawRectangle(x - 1, y - 1, width + 2, height);
+        t.draw();
 
         glEnable(GL_TEXTURE_2D);
 
 //		fontrenderer.drawStringWithShadow(string, x, y, 0xFFFFFF);
-        font.drawString(string, x, y, 0xFFFFFF);
+        drawStringNoShadow(this.fontRenderer, string, x, y, 0xFFFFFF);
     }
 
-    private void drawDebugScreenLine(String string)
+    private void drawDebugScreenLine(final CharSequence string)
     {
-        drawDebugScreenLine(string, false, debugLine++, debugOffset);
+        drawDebugScreenLine(string, false, this.debugLine++, this.debugOffset);
     }
 
-    private void drawDebugScreenLineRight(String string)
+    private void drawDebugScreenLineRight(final CharSequence string)
     {
-        drawDebugScreenLine(string, true, debugLineRight++, debugOffsetRight);
+        drawDebugScreenLine(string, true, this.debugLineRight++, this.debugOffsetRight);
     }
 
     private final List<String> playerListScoreStrings = new ArrayList<>();
@@ -722,9 +721,9 @@ public class HudIngame extends Gui
 
         for (Map.Entry<String, String> a1 : players.entrySet())
         {
-            longestNameWidth = java.lang.Math.max(font.getStringWidth(a1.getKey()), longestNameWidth);
+            longestNameWidth = Math.max(MathHelper.ceil(this.fontRenderer.stringWidthDouble(a1.getKey())), longestNameWidth);
 
-            longestScoreWidth = java.lang.Math.max(font.getStringWidth(a1.getValue()), longestScoreWidth);
+            longestScoreWidth = Math.max(MathHelper.ceil(this.fontRenderer.stringWidthDouble(a1.getValue())), longestScoreWidth);
             playerListScoreStrings.add(a1.getValue());
         }
 
@@ -768,11 +767,11 @@ public class HudIngame extends Gui
             int posX = listX + x * columnWidth + x * innerPadding + outerPadding;
             int posY = listY + y * lineHeight + y * innerPadding + outerPadding;
 
-            int scoreStringWidth = font.getStringWidth(a2.getValue());
+            int scoreStringWidth = MathHelper.ceil(fontRenderer.stringWidthDouble(a2.getValue()));
             drawRect(posX - 2, posY - 2, posX + columnWidth + 2, posY + 10, 0xffa5a5a5);
             drawRect(posX - 1, posY - 1, posX + columnWidth + 1, posY + 9, 0xA8080808);
-            font.drawStringWithShadow(a2.getKey(), posX, posY, 0xFFFFFF);
-            font.drawStringWithShadow(TextFormatting.YELLOW + a2.getValue(), posX + columnWidth - scoreStringWidth, posY, 0xFFFFFF);
+            drawStringShadow(this.fontRenderer,a2.getKey(), posX, posY, 0xFFFFFF);
+            drawStringShadow(this.fontRenderer,TextFormatting.YELLOW + a2.getValue(), posX + columnWidth - scoreStringWidth, posY, 0xFFFFFF);
             i++;
         }
     }
@@ -798,7 +797,7 @@ public class HudIngame extends Gui
                 {
                     k4 = Color.HSBtoRGB(f2 / 50F, 0.7F, 0.6F) & 0xffffff;
                 }
-                font.drawString(recordPlaying, -font.getStringWidth(recordPlaying) / 2, -4, k4 + (j3 << 24));
+                drawStringNoShadow(this.fontRenderer, recordPlaying, MathHelper.ceil(-fontRenderer.stringWidthDouble(recordPlaying) / 2), -4, k4 + (j3 << 24));
                 GL11.glDisable(3042 /* GL_BLEND */);
                 GL11.glPopMatrix();
             }
@@ -808,18 +807,18 @@ public class HudIngame extends Gui
     public void drawChat(int width, int height, int sp)
     {
         if (mc.gameSettings.chatVisibility.value == ChatVisibility.NEVER_SHOW) return;
-        int messagesToShow = 10;
+        int linesToShow = 10;
         boolean ignoreFadeout = false;
         if (mc.currentScreen instanceof ScreenChat)
         {
             int acceptableSize = height - 48 - 48;
-            messagesToShow = acceptableSize / 9;
+            linesToShow = acceptableSize / 9;
             ignoreFadeout = true;
         } else if (mc.gameSettings.chatVisibility.value == ChatVisibility.SHOW_WHEN_CHATTING) {
             return;
         }
 
-        if (chatScroll > chatMessageList.size() - messagesToShow) chatScroll = chatMessageList.size() - messagesToShow;
+        if (chatScroll > chatMessageList.size() - linesToShow) chatScroll = chatMessageList.size() - linesToShow;
         if (chatScroll < 0) chatScroll = 0;
 
         GL11.glEnable(GL_BLEND);
@@ -827,13 +826,15 @@ public class HudIngame extends Gui
         GL11.glDisable(GL_ALPHA_TEST);
         GL11.glPushMatrix();
         GL11.glTranslatef(0.0F, height - 48, 0.0F);
-        for (int i = chatScroll; i < chatMessageList.size() && i < chatScroll + messagesToShow; i++)
-        {
-            if (chatMessageList.get(i).updateCounter >= 190 && !ignoreFadeout)
+        int y = -12;
+        for (int i = 0; i < linesToShow; i++) {
+            if (this.chatScroll + i >= this.chatMessageList.size()) continue;
+            final ChatLine line = this.chatMessageList.get(this.chatScroll + i);
+            if (line.updateCounter >= 190 && !ignoreFadeout)
             {
                 continue;
             }
-            double fadeAmount = (double) chatMessageList.get(i).updateCounter / 200D;
+            double fadeAmount = (double) line.updateCounter / 200D;
             fadeAmount = 1.0D - fadeAmount;
             fadeAmount *= 10D;
             if (fadeAmount < 0.0D)
@@ -852,12 +853,13 @@ public class HudIngame extends Gui
             }
             if (alpha > 0)
             {
-                byte xPad = 2;
-                int y = -(i - chatScroll) * 9 - 12;
-                String s1 = chatMessageList.get(i).message;
-                drawRect(xPad, y - 1 - sp, xPad + 320, y + 8 - sp, alpha / 2 << 24);
+                final CharSequence message = line.message;
+                final byte xPad = 2;
+                final int h = MathHelper.ceil( this.fontRenderer.heightOfConstrainedChars(message, MAX_CHAT_WIDTH));
+                y -= (h + 2);
+                drawRect(xPad, y - sp - 1, xPad + MAX_CHAT_WIDTH, y + h - sp + 1, alpha / 2 << 24);
                 GL11.glEnable(GL_BLEND);
-                mc.font.drawStringWithShadow(s1, xPad, y - sp, 0xFFFFFF + (alpha << 24));
+                FontHelper.renderWidthConstrained(Tessellator.instance, message, xPad, y, MAX_CHAT_WIDTH).setShadow().setColor(0xFFFFFF + (alpha << 24)).call(this.fontRenderer);
             }
         }
 
@@ -985,37 +987,12 @@ public class HudIngame extends Gui
         chatMessageList.clear();
     }
 
-    public void addChatMessage(String s)
+    public void addChatMessage(final CharSequence s)
     {
         LOGGER.info("[CHAT] {}", s);
-        int i;
-        TextFormatting activeFormatting = null;
-        while (mc.font.getStringWidth(s) > 320)
-        {
-            for (i = 1; i < s.length() && mc.font.getStringWidth(s.substring(0, i + 1)) <= 320; i++) {
-                char c = s.charAt(i - 1);
-                if (c == '§') {
-                    char code = s.charAt(i);
-                    for (TextFormatting formatting : TextFormatting.FORMATTINGS) {
-                        if (formatting.code == code) {
-                            activeFormatting = formatting;
-                            break;
-                        }
-                    }
-                }
-            }
-            addChatMessage(s.substring(0, i));
-            if (activeFormatting != null) {
-                s = "" + '§' + activeFormatting.code + s.substring(i);
-            } else {
-                s = s.substring(i);
-            }
-        }
-
-        chatMessageList.add(0, new ChatLine(s));
-        while (chatMessageList.size() > 100)
-        {
-            chatMessageList.remove(chatMessageList.size() - 1);
+        this.chatMessageList.add(0, new ChatLine(s));
+        while (this.chatMessageList.size() > 100) {
+            this.chatMessageList.remove(this.chatMessageList.size() - 1);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java
index 5d31bc3be..309b28ca1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/HudIngameDoom.java
@@ -5,7 +5,6 @@ import net.minecraft.client.gui.ScreenPhotoMode;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.enums.HumanArmorShape;
-import net.minecraft.core.item.IArmorItem;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.net.command.TextFormatting;
 import org.lwjgl.opengl.GL11;
@@ -223,7 +222,7 @@ public class HudIngameDoom
         }
 
         drawTexturedModalRect(x, y, u, v, 13, 13);
-        drawString(font, Integer.toString(number % 10), x + 4, y + 3, textColor);
+        drawStringShadow(fontRenderer, Integer.toString(number % 10), x + 4, y + 3, textColor);
     }
 
     private void drawArmor()
@@ -289,11 +288,11 @@ public class HudIngameDoom
         name = name.toUpperCase();
         if (selected)
         {
-            drawString(font, TextFormatting.get(stack.getDisplayColor()) + name, x, y, 0xFFFFFFFF);
+            drawStringShadow(fontRenderer, TextFormatting.get(stack.getDisplayColor()) + name, x, y, 0xFFFFFFFF);
         }
         else
         {
-            drawStringNoShadow(font, name, x, y, 0xFF404040);
+            drawStringNoShadow(fontRenderer, name, x, y, 0xFF404040);
         }
 
         int maxStackSize = stack.getMaxStackSize();
@@ -302,21 +301,21 @@ public class HudIngameDoom
         // Draw stack size
         if (stackSize < 10)
         {
-            drawString(font, Integer.toString(stackSize), x + 70, y, 0xFFFFFFA0);
+            drawStringShadow(fontRenderer, Integer.toString(stackSize), x + 70, y, 0xFFFFFFA0);
         }
         else
         {
-            drawString(font, Integer.toString(stackSize), x + 64, y, 0xFFFFFFA0);
+            drawStringShadow(fontRenderer, Integer.toString(stackSize), x + 64, y, 0xFFFFFFA0);
         }
 
         // Draw max stack size
         if (maxStackSize < 10)
         {
-            drawString(font, Integer.toString(maxStackSize), x + 88, y, 0xFFFFFFA0);
+            drawStringShadow(fontRenderer, Integer.toString(maxStackSize), x + 88, y, 0xFFFFFFA0);
         }
         else
         {
-            drawString(font, Integer.toString(maxStackSize), x + 82, y, 0xFFFFFFA0);
+            drawStringShadow(fontRenderer, Integer.toString(maxStackSize), x + 82, y, 0xFFFFFFA0);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HubComponentSubtitles.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HubComponentSubtitles.java
index ae7c390f9..ca6913b97 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HubComponentSubtitles.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HubComponentSubtitles.java
@@ -5,6 +5,8 @@ import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
 import net.minecraft.client.gui.subtitles.SubtitleTracker;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.sound.SoundRepository;
 import org.lwjgl.opengl.GL11;
 
@@ -58,12 +60,12 @@ public class HubComponentSubtitles extends HudComponentMovable {
             if (entry.soundEvent == null) {
                 continue;
             }
-            int msgWidth = mc.font.getStringWidth(entry.soundEvent.getSubtitleTranslated());
+            int msgWidth = mc.font.stringWidth(entry.soundEvent.getSubtitleTranslated());
             if (msgWidth > maxMessageWidth) {
                 maxMessageWidth = msgWidth;
             }
         }
-        maxMessageWidth += mc.font.getStringWidth("<") + mc.font.getStringWidth(">");
+        maxMessageWidth += mc.font.stringWidth("<") + mc.font.stringWidth(">");
 
         GL11.glEnable(GL_BLEND);
         GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -96,16 +98,18 @@ public class HubComponentSubtitles extends HudComponentMovable {
             {
                 byte xPad = 3;
                 int y2 = -i * 9 - 8;
-                String s1 = entry.soundEvent.getSubtitleTranslated();
-                gui.drawRect(xRight - maxMessageWidth - xPad * 2, yBottom + y2 - 1, xRight, yBottom + y2 + 8, alpha / 2 << 24);
-                GL11.glEnable(GL_BLEND);
-                mc.font.drawCenteredString(s1, xRight - (maxMessageWidth) / 2 - xPad, yBottom + y2, 0xFFFFFF + (alpha << 24));
-                if (mc.thePlayer != null) {
-                    double sin = Math.sin(entry.getRelativeAngle(mc.thePlayer) + Math.PI/2);
-                    if (sin > 0.7) {
-                        mc.font.drawString("<", xRight - maxMessageWidth - xPad, yBottom + y2, 0xFFFFFF + (alpha << 24));
-                    } else if (sin < -0.7) {
-                        mc.font.drawString(">", xRight - mc.font.getStringWidth(">") - xPad/2, yBottom + y2, 0xFFFFFF + (alpha << 24));
+                final String subtitle = entry.soundEvent.getSubtitleTranslated();
+                if (subtitle != null) {
+                    gui.drawRect(xRight - maxMessageWidth - xPad * 2, yBottom + y2 - 1, xRight, yBottom + y2 + 8, alpha / 2 << 24);
+                    GL11.glEnable(GL_BLEND);
+                    FontHelper.renderCentered(Tessellator.instance, subtitle, xRight - (maxMessageWidth) / 2 - xPad, yBottom + y2).setShadow().setColor(0xFFFFFF + (alpha << 24)).call(mc.font);
+                    if (mc.thePlayer != null) {
+                        final double sin = Math.sin(entry.getRelativeAngle(mc.thePlayer) + Math.PI/2);
+                        if (sin > 0.7) {
+                            FontHelper.render(Tessellator.instance, "<", xRight - maxMessageWidth - xPad, yBottom + y2).setColor(0xFFFFFF + (alpha << 24)).call(mc.font);
+                        } else if (sin < -0.7) {
+                            FontHelper.render(Tessellator.instance, ">", xRight - mc.font.stringWidth(">") - xPad/2, yBottom + y2).setColor(0xFFFFFF + (alpha << 24)).call(mc.font);
+                        }
                     }
                 }
             }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentLog.java b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentLog.java
index 7686689ee..aa4fe23b9 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentLog.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/hud/component/HudComponentLog.java
@@ -8,7 +8,9 @@ import net.minecraft.client.gui.hud.HudIngame;
 import net.minecraft.client.gui.hud.component.layout.Layout;
 import net.minecraft.client.gui.hud.component.layout.LayoutAbsolute;
 import net.minecraft.client.gui.hud.component.layout.LayoutSnap;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.net.command.TextFormatting;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -79,13 +81,13 @@ public class HudComponentLog extends HudComponentMovable {
                 if (message.getMessage().startsWith("[CHAT] ")) return;
 
                 final @NotNull String ellipsis = "...";
-                final int ellipsisWidth = mc.font.getStringWidth(ellipsis);
+                final int ellipsisWidth = mc.font.stringWidth(ellipsis);
 
                 @NotNull String line = message.getMessage().replace("\n", "");
                 int acc = 0;
                 int c = 0;
                 for (; c < line.length(); c++) {
-                    final int cWidth = mc.font.getCharWidth(line.charAt(c));
+                    final int cWidth = mc.font.charWidth(line.charAt(c));
                     if (acc + cWidth + ellipsisWidth > WIDTH) {
                         break;
                     }
@@ -157,19 +159,19 @@ public class HudComponentLog extends HudComponentMovable {
         render(mc.font, x, y, lines, new float[] { 1.0f, 1.0f, 1.0f, 1.0f }, anchor);
     }
 
-    private void render(final @NotNull Font font, final int x, final int y, final @NotNull String @NotNull[] lines, final float @NotNull[] opacities, final @Nullable ComponentAnchor anchor) {
+    private void render(final @NotNull FontRenderer sr, final int x, final int y, final @NotNull String @NotNull[] lines, final float @NotNull[] opacities, final @Nullable ComponentAnchor anchor) {
         GL11.glEnable(GL11.GL_BLEND);
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
         for (int i = 0; i < lines.length; i++) {
             @NotNull String line = lines[i];
 
-            final int lineWidth = font.getStringWidth(line);
+            final int lineWidth = sr.stringWidth(line);
             if (anchor == null || anchor == ComponentAnchor.TOP_LEFT || anchor == ComponentAnchor.CENTER_LEFT || anchor == ComponentAnchor.BOTTOM_LEFT) {
-                font.drawStringWithShadow(line, x + PADDING, y + PADDING + i * LINE_HEIGHT, 0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24));
+                FontHelper.render(Tessellator.instance, line, x + PADDING, y + PADDING + i * LINE_HEIGHT).setShadow().setColor(0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24)).call(sr);
             } else if (anchor == ComponentAnchor.TOP_CENTER || anchor == ComponentAnchor.CENTER || anchor == ComponentAnchor.BOTTOM_CENTER) {
-                font.drawStringWithShadow(line, x + PADDING + WIDTH / 2 - lineWidth / 2, y + PADDING + i * LINE_HEIGHT, 0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24));
+                FontHelper.render(Tessellator.instance, line, x + PADDING + WIDTH / 2 - lineWidth / 2, y + PADDING + i * LINE_HEIGHT).setShadow().setColor(0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24)).call(sr);
             } else {
-                font.drawStringWithShadow(line, x + PADDING + WIDTH - lineWidth, y + PADDING + i * LINE_HEIGHT, 0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24));
+                FontHelper.render(Tessellator.instance, line, x + PADDING + WIDTH - lineWidth, y + PADDING + i * LINE_HEIGHT).setShadow().setColor(0x00_FF_FF_FF + ((int)(opacities[i] * 0xFF) << 24)).call(sr);
             }
         }
         GL11.glDisable(GL11.GL_BLEND);
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 a698d9b3b..9293a7038 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
@@ -61,7 +61,7 @@ public class ScreenKeyboard extends Screen implements ITextField {
         Keyboard.enableRepeatEvents(true);
         if (parent != null) {
             parent.mc = mc;
-            parent.font = mc.font;
+            parent.fontRenderer = mc.font;
             parent.width = width;
             parent.height = height;
         }
@@ -231,17 +231,17 @@ public class ScreenKeyboard extends Screen implements ITextField {
 
         Arrays.stream(keyboardLayout.getKeys()).forEach(key -> key.render(mc, this, _x, _y, mx, my));
 
-        drawStringCentered(mc.font, editor.getText(), _x + keyboardWidth/2, _y - 20, 0xFFFFFF);
+        drawStringCenteredShadow(mc.font, editor.getText(), _x + keyboardWidth/2, _y - 20, 0xFFFFFF);
 
         boolean drawCursor = (cursorCounter / 6) % 2 == 0;
         if (drawCursor)
         {
-            int width = font.getStringWidth(editor.getText());
+            int width = MathHelper.ceil(fontRenderer.stringWidthDouble(editor.getText()));
             if (editor.getCursor() < editor.getText().length())
             {
-                width = font.getStringWidth(editor.getText().substring(0, editor.getCursor()));
+                width = MathHelper.ceil(fontRenderer.stringWidthDouble(editor.getText().substring(0, editor.getCursor())));
             }
-            drawString(font, "_", _x + keyboardWidth/2 - font.getStringWidth(editor.getText())/2 + width, _y - 20 + 1, 0xE0E0E0);
+            drawStringShadow(fontRenderer, "_", _x + keyboardWidth/2 - MathHelper.ceil(fontRenderer.stringWidthDouble(editor.getText())/2) + width, _y - 20 + 1, 0xE0E0E0);
         }
 
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/keyboard/keys/CharKey.java b/game/client/src/main/java/net/minecraft/client/gui/keyboard/keys/CharKey.java
index c6d8c92c1..29013ee1c 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/keyboard/keys/CharKey.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/keyboard/keys/CharKey.java
@@ -1,6 +1,5 @@
 package net.minecraft.client.gui.keyboard.keys;
 
-import com.b100.utils.StringUtils;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonDeserializationContext;
 import com.google.gson.JsonDeserializer;
@@ -20,9 +19,7 @@ import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
 
 import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
@@ -55,7 +52,7 @@ public class CharKey extends Key{
                 GL11.glColor4f(0.75f, 0.75f, 0.75f, 1f);
                 GL11.glTranslatef(x + originX + 4, y + originY + 2, 0);
                 GL11.glScalef(0.75f, 0.75f, 1);
-                drawStringCentered(mc.font, String.valueOf(keyboard.isModifierActive(ModifierKey.ID_MODIFIER_SHIFT) ? lastGroup.collections[0].upper : lastGroup.collections[0].lower), 0, 0, 0xE0E0E0);
+                drawStringCenteredShadow(mc.font, String.valueOf(keyboard.isModifierActive(ModifierKey.ID_MODIFIER_SHIFT) ? lastGroup.collections[0].upper : lastGroup.collections[0].lower), 0, 0, 0xE0E0E0);
                 GL11.glPopMatrix();
             }
 
@@ -64,7 +61,7 @@ public class CharKey extends Key{
                 GL11.glColor4f(0.75f, 0.75f, 0.75f, 1f);
                 GL11.glTranslatef(x + width + originX - 4, y + originY + 2, 0);
                 GL11.glScalef(0.75f, 0.75f, 1);
-                drawStringCentered(mc.font, String.valueOf(keyboard.isModifierActive(ModifierKey.ID_MODIFIER_SHIFT) ? nextGroup.collections[0].upper : nextGroup.collections[0].lower), 0, 0, 0xE0E0E0);
+                drawStringCenteredShadow(mc.font, String.valueOf(keyboard.isModifierActive(ModifierKey.ID_MODIFIER_SHIFT) ? nextGroup.collections[0].upper : nextGroup.collections[0].lower), 0, 0, 0xE0E0E0);
                 GL11.glPopMatrix();
             }
         }
@@ -86,7 +83,7 @@ public class CharKey extends Key{
                 size,
                 TextureRegistry.getTexture("minecraft:gui/screen/keyboard/radial_background"));
 
-            drawStringCentered(mc.font, String.valueOf(getActiveChar(mc, keyboard, originX, originY, mouseX, mouseY)), x + width/2 + originX, y + mc.font.fontHeight/2 + 4 + originY, texColor);
+            drawStringCenteredShadow(mc.font, String.valueOf(getActiveChar(mc, keyboard, originX, originY, mouseX, mouseY)), x + width/2 + originX, y + mc.font.fontHeight()/2 + 4 + originY, texColor);
 
             final double dx;
             final double dy;
@@ -107,7 +104,7 @@ public class CharKey extends Key{
                 int charX = MathHelper.floor(x + originX + width/2d + Math.cos(r * i - Math.PI/2) * 20 * animProgress);
                 int charY = MathHelper.floor(y + originY + height/2d + Math.sin(r * i - Math.PI/2) * 20 * animProgress) - 3;
 
-                drawStringCentered(
+                drawStringCenteredShadow(
                     mc.font,
                     String.valueOf(keyboard.isModifierActive(ModifierKey.ID_MODIFIER_SHIFT) ? collection.upper : collection.lower),
                     charX,
@@ -117,7 +114,7 @@ public class CharKey extends Key{
             GL11.glDisable(GL11.GL_BLEND);
             GL11.glPopMatrix();
         } else {
-            drawStringCentered(mc.font, String.valueOf(getActiveChar(mc, keyboard, originX, originY, mouseX, mouseY)), x + width/2 + originX, y + mc.font.fontHeight/2 + 4 + originY, texColor);
+            drawStringCenteredShadow(mc.font, String.valueOf(getActiveChar(mc, keyboard, originX, originY, mouseX, mouseY)), x + width/2 + originX, y + mc.font.fontHeight()/2 + 4 + originY, texColor);
         }
         GL11.glColor4f(1f, 1f, 1f, 1f);
     }
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 5ce0c784d..3e9af8a67 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
@@ -15,20 +15,16 @@ import net.minecraft.client.gui.modelviewer.elements.ListenerTextFieldElement;
 import net.minecraft.client.gui.modelviewer.elements.IListenerElement;
 import net.minecraft.client.gui.options.ScreenOptions;
 import net.minecraft.client.gui.options.data.OptionsPages;
-import net.minecraft.client.render.TileEntityRenderDispatcher;
 import net.minecraft.client.render.shader.PhotoModeRenderer;
 import net.minecraft.client.render.shader.Shaders;
 import net.minecraft.client.render.shader.ShadersRenderer;
-import net.minecraft.client.render.tessellator.Tessellator;
 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.block.Blocks;
-import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.Buffer;
-import net.minecraft.core.util.helper.Utils;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -245,7 +241,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
 
         buttons.addAll(leftSideButtons);
 
-        ListenerTextFieldElement rField = new ListenerTextFieldElement(this, font, 0, j++ * 21, 40, 20, String.valueOf(bgRed), "Red");
+        ListenerTextFieldElement rField = new ListenerTextFieldElement(this, fontRenderer, 0, j++ * 21, 40, 20, String.valueOf(bgRed), "Red");
         rField.setPrefaceText("R: ");
         rField.setKeyListener(key -> {
             try {
@@ -258,7 +254,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
                 bgRed = defaultRed;
             }
         });
-        ListenerTextFieldElement gField = new ListenerTextFieldElement(this, font, 40, rField.yPosition, 40, 20, String.valueOf(bgGreen), "Green");
+        ListenerTextFieldElement gField = new ListenerTextFieldElement(this, fontRenderer, 40, rField.yPosition, 40, 20, String.valueOf(bgGreen), "Green");
         gField.setPrefaceText("G: ");
         gField.setKeyListener(key -> {
             try {
@@ -271,7 +267,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
                 bgGreen = defaultGreen;
             }
         });
-        ListenerTextFieldElement bField = new ListenerTextFieldElement(this, font, 80, rField.yPosition, 40, 20, String.valueOf(bgBlue), "Blue");
+        ListenerTextFieldElement bField = new ListenerTextFieldElement(this, fontRenderer, 80, rField.yPosition, 40, 20, String.valueOf(bgBlue), "Blue");
         bField.setPrefaceText("B: ");
         bField.setKeyListener(key -> {
             try {
@@ -384,7 +380,7 @@ public class ScreenModelViewer extends ScreenPhotoMode implements ListenerTextFi
 
 //        TileEntityRenderDispatcher.instance.renderTileEntity(Tessellator.instance, new TileEntity(), -0.5D, -0.75D, -0.5D, partialTick);
 
-        drawStringCentered(font, currentCategory.getCurrentDisplayInfo(I18n.getInstance()), width/2, 1, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, currentCategory.getCurrentDisplayInfo(I18n.getInstance()), width/2, 1, 0xffffff);
     }
     @Override
     public void keyPressed(char eventCharacter, int eventKey, int mx, int my)
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/ListenerTextFieldElement.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/ListenerTextFieldElement.java
index 59b149d99..6fcd2c098 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/ListenerTextFieldElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/ListenerTextFieldElement.java
@@ -4,11 +4,12 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.gui.text.ITextField;
 import net.minecraft.client.gui.text.TextFieldEditor;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.input.Keyboard;
 
 public class ListenerTextFieldElement extends ListenerButtonElement implements ITextField {
-    private final Font font;
+    private final FontRenderer fontRenderer;
     private String text = "";
     private String prefaceText = "";
     private int maxStringLength;
@@ -22,14 +23,14 @@ public class ListenerTextFieldElement extends ListenerButtonElement implements I
     public boolean drawBackground = true;
     public final TextFieldEditor editor;
 
-    public ListenerTextFieldElement(Screen parent, Font font, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder)
+    public ListenerTextFieldElement(Screen parent, FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder)
     {
         super(-1, xPosition, yPosition, width, height, "");
         playSound = false;
         isFocused = false;
         isEnabled = true;
         this.parent = parent;
-        this.font = font;
+        this.fontRenderer = fontRenderer;
         this.editor = new TextFieldEditor(this);
         this.placeholder = placeholder;
         setText(defaultText);
@@ -118,24 +119,24 @@ public class ListenerTextFieldElement extends ListenerButtonElement implements I
         }
         if (text.isEmpty() && !isFocused)
         {
-            drawString(font, placeholder, xPosition + 4, yPosition + (height - 8) / 2, 0x5f5f5f);
+            drawStringShadow(fontRenderer, placeholder, xPosition + 4, yPosition + (height - 8) / 2, 0x5f5f5f);
         }
 
         if(isEnabled)
         {
             boolean drawCursor = isFocused && (cursorCounter / 6) % 2 == 0;
             int cursor = editor.getCursor();
-            int maxDisplayableChars = this.width / font.getCharWidth('_');
+            int maxDisplayableChars = this.width / fontRenderer.charWidth('_');
 
             if (!text.isEmpty() || isFocused){
                 if(prefaceText.length() + text.length() <= maxDisplayableChars-1){
-                    drawString(font, prefaceText + text, xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                    drawStringShadow(fontRenderer, prefaceText + text, xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
                 } else {
                     //only draw the part of the string that's maxDisplayableChars chars around the cursor
                     String newString = prefaceText + text;
                     int begin = Math.max(0,cursor - maxDisplayableChars);
                     int end = Math.max(maxDisplayableChars,Math.min(newString.length(),cursor));
-                    drawString(font, newString.substring(begin, end), xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                    drawStringShadow(fontRenderer, newString.substring(begin, end), xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
                 }
             }
             if (drawCursor)
@@ -144,21 +145,21 @@ public class ListenerTextFieldElement extends ListenerButtonElement implements I
                 if (!text.isEmpty() || isFocused){
                     currentText = prefaceText + text;
                 }
-                int width = font.getStringWidth(currentText);
+                int width = MathHelper.ceil(fontRenderer.stringWidthDouble(currentText));
                 if (cursor < text.length())
                 {
-                    width = font.getStringWidth(text.substring(0, cursor)) + font.getStringWidth(prefaceText);
+                    width = MathHelper.ceil(fontRenderer.stringWidthDouble(text.substring(0, cursor)) + fontRenderer.stringWidthDouble(prefaceText));
                 }
                 if(width >= this.width-4){
                     // width of the text box - the width of the last character
-                    width = (this.width-4) - font.getStringWidth(currentText.substring(currentText.length()-2,currentText.length()-1));
+                    width = (this.width-4) - MathHelper.ceil(fontRenderer.stringWidthDouble(currentText.substring(currentText.length()-2,currentText.length()-1)));
                 }
-                drawString(font, "_", xPosition + 4 + width, yPosition + (height - 8) / 2, 0xE0E0E0);
+                drawStringShadow(fontRenderer, "_", xPosition + 4 + width, yPosition + (height - 8) / 2, 0xE0E0E0);
             }
         }
         else
         {
-            drawString(font, text, xPosition + 4, yPosition + (height - 8) / 2, 0x707070);
+            drawStringShadow(fontRenderer, text, xPosition + 4, yPosition + (height - 8) / 2, 0x707070);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/TextCycleElement.java b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/TextCycleElement.java
index 7eff42c73..e6bf19dd0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/TextCycleElement.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/modelviewer/elements/TextCycleElement.java
@@ -2,7 +2,7 @@ package net.minecraft.client.gui.modelviewer.elements;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.Screen;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
 
 public abstract class TextCycleElement<T> extends ListenerButtonElement {
     private T currentElement;
@@ -10,10 +10,10 @@ public abstract class TextCycleElement<T> extends ListenerButtonElement {
     public final ListenerButtonElement prevButton;
     public final ListenerButtonElement nextButton;
     public final ListenerTextFieldElement textField;
-    public TextCycleElement(Screen parent, Font font, int xPosition, int yPosition, int width, int height, T initialElement) {
+    public TextCycleElement(Screen parent, FontRenderer sr, int xPosition, int yPosition, int width, int height, T initialElement) {
         super(-1, xPosition, yPosition, width, height, "");
 
-        textField = new ListenerTextFieldElement(parent, font, 0, yPosition, width - height * 2 - 2, height, getNameFromElement(initialElement), "");
+        textField = new ListenerTextFieldElement(parent, sr, 0, yPosition, width - height * 2 - 2, height, getNameFromElement(initialElement), "");
         textField.setKeyListener(key -> {
             String text = textField.getText();
             setCurrentElement(getElementFromString(text));
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 2731a54a4..6784fb64e 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
@@ -128,7 +128,7 @@ public class ScreenOptions
                 textColor = 0xFFFFFFA0;
             }
             renderItem.render(page.getIcon(), x, y2 + (PAGE_BUTTON_HEIGHT / 2) - 9);
-            mc.font.drawStringWithShadow(translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
+            drawStringShadow(this.fontRenderer, translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
             y2 += PAGE_BUTTON_HEIGHT;
         }
     }
@@ -303,7 +303,7 @@ public class ScreenOptions
         overlayBackground(pagesListWidth, pagesListWidth + SEPARATOR_WIDTH, top, bottom);
 
         String titleLanguageKey = "gui.options.title";
-        drawStringCentered(font, i18n.translateKey(titleLanguageKey), width / 2, 5, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey(titleLanguageKey), width / 2, 5, 0xffffff);
 
         drawOptionsScrollBar(mx, my);
         drawPagesListScrollBar(mx, my);
@@ -312,7 +312,7 @@ public class ScreenOptions
 
         if (pickingKeyBinding != null && pickingKeyBindingComponent != null) {
             drawRect(0, 0, width, height, 0xA0000000);
-            drawStringCenteredNoShadow(font, i18n.translateKeyAndFormat("gui.options.label.picking_keybinding", i18n.translateKey(pickingKeyBinding.getId())), width / 2, height / 2 - 4, 0xffffff);
+            drawStringCenteredNoShadow(fontRenderer, i18n.translateKeyAndFormat("gui.options.label.picking_keybinding", i18n.translateKey(pickingKeyBinding.getId())), width / 2, height / 2 - 4, 0xffffff);
         }
     }
 
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/AvailableTexturePackListComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/AvailableTexturePackListComponent.java
index 0634b81e7..ebd819aa1 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/AvailableTexturePackListComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/AvailableTexturePackListComponent.java
@@ -6,11 +6,11 @@ import java.util.ArrayList;
 import java.util.List;
 
 import net.minecraft.client.gui.ButtonElement;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.core.sound.SoundCategory;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texturepack.TexturePack;
 import net.minecraft.client.util.helper.Colors;
@@ -73,7 +73,7 @@ public class AvailableTexturePackListComponent
     @Override
     public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         if (availablePacks.isEmpty()) {
-            mc.font.drawCenteredString(I18n.getInstance().translateKey("gui.options.page.texture_packs.label.no_packs"), x + width / 2, y + 4, 0x5F7F7F7F);
+            FontHelper.renderCentered(Tessellator.instance, I18n.getInstance().translateKey("gui.options.page.texture_packs.label.no_packs"), x + width / 2, y + 4).setShadow().setColor(0x5F7F7F7F).call(mc.font);
         }
         for (int i = 0; i < availablePacks.size(); i++) {
             TexturePackButton button = availablePacks.get(i);
@@ -127,7 +127,6 @@ public class AvailableTexturePackListComponent
 
         public void render(int x, int y, int width, int mouseX, int mouseY, int index, boolean hovered) {
             Tessellator tessellator = Tessellator.instance;
-            Font font = mc.font;
 
             setupButton(x, y, width, mouseX, mouseY);
 
@@ -170,21 +169,21 @@ public class AvailableTexturePackListComponent
 
 			if(format == Global.TEXTURE_PACK_FORMAT) {
 				// Correct version
-				font.drawString(texturePack.manifest.getName(), x + height + 2, y + 1, 0xFFFFFF);
-				font.drawString(texturePack.manifest.getDescriptionLine1(), x + height + 2, y + 12, 0x808080);
-				font.drawString(texturePack.manifest.getDescriptionLine2(), x + height + 2, y + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getName(), x + this.height + 2, y + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine1(), x + this.height + 2, y + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine2(), x + this.height + 2, y + 22).setColor(0x808080).call(mc.font);
 			}else if(format == -1) {
 				// Manifest error
-				font.drawString(TextFormatting.RED + texturePack.manifest.getName(), x + height + 2, y + 1, 0xFFFFFF);
-				font.drawString(texturePack.manifest.getDescriptionLine1(), x + height + 2, y + 12, 0x808080);
-				font.drawString(texturePack.manifest.getDescriptionLine2(), x + height + 2, y + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, TextFormatting.RED + this.texturePack.manifest.getName(), x + this.height + 2, y + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine1(), x + this.height + 2, y + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine2(), x + this.height + 2, y + 22).setColor(0x808080).call(mc.font);
 				rgbVersion = Colors.allChatColors[TextFormatting.RED.id].getARGB();
 			}else {
 				// Wrong texture pack version
 				I18n i18n = I18n.getInstance();
-				font.drawString(TextFormatting.RED + texturePack.manifest.getName(), x + height + 2, y + 1, 0xFFFFFF);
-				font.drawString(i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.1"), x + height + 2, y + 12, 0x808080);
-				font.drawString(i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.2"), x + height + 2, y + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, TextFormatting.RED + this.texturePack.manifest.getName(), x + this.height + 2, y + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.1"), x + this.height + 2, y + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.2"), x + this.height + 2, y + 22).setColor(0x808080).call(mc.font);
 				rgbVersion = Colors.allChatColors[TextFormatting.RED.id].getARGB();
 			}
 
@@ -194,8 +193,8 @@ public class AvailableTexturePackListComponent
             }
 
             String version = texturePack.manifest.getPackVersion();
-            int versionWidth = font.getStringWidth(version);
-            font.drawString(texturePack.manifest.getPackVersion(), x + width - versionWidth - 2, y + 1, rgbVersion);
+            int versionWidth = mc.font.stringWidth(version);
+            FontHelper.render(Tessellator.instance, texturePack.manifest.getPackVersion(), x + width - versionWidth - 2, y + 1).setColor(rgbVersion).call(mc.font);
         }
         public void setupButton(int x, int y, int width, int mouseX, int mouseY){
             button.setX(x + width - button.width - 1);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/ButtonComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/ButtonComponent.java
index 762dff32c..db2477777 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/ButtonComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/ButtonComponent.java
@@ -2,7 +2,7 @@ package net.minecraft.client.gui.options.components;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.window.CursorShape;
 import net.minecraft.core.lang.I18n;
@@ -42,16 +42,15 @@ public abstract class ButtonComponent
     @Override
     public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY)
     {
-        Font fr = mc.font;
         String translated = I18n.getInstance().translateKey(translationKey);
         int textColor = 0xFFFFFFFF;
         if (relativeMouseX >= 0 && relativeMouseX <= width && relativeMouseY >= COMPONENT_SPACING && relativeMouseY <= getHeight() - COMPONENT_SPACING) {
             textColor = 0xFFFFFFA0;
         }
-        fr.drawStringWithShadow(translated, x, y + (getHeight() / 2) - 4, textColor);
+        FontHelper.render(Tessellator.instance, translated, x, y + (getHeight() / 2) - 4).setShadow().setColor(textColor).call(mc.font);
         resetButton.enabled = !isDefault();
         renderButton(x, y, width - BUTTON_WIDTH, COMPONENT_SPACING, BUTTON_WIDTH, 20, relativeMouseX, relativeMouseY);
-        int stringWidth = fr.getStringWidth(translated);
+        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);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
index caeac86ae..169e03488 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/LanguagePackListComponent.java
@@ -2,7 +2,7 @@ package net.minecraft.client.gui.options.components;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.lang.Language;
@@ -97,7 +97,6 @@ public class LanguagePackListComponent
         }
 
         public void render(int x, int y, int width, int mouseX, int mouseY) {
-            Font textRenderer = mc.font;
             Tessellator tessellator = Tessellator.instance;
 
             if (mc.gameSettings.language.value.equals(languagePack.getId())) {
@@ -132,28 +131,19 @@ public class LanguagePackListComponent
             if (region != null) {
                 sb.append(" (").append(region).append(")");
             }
-            String fullName = sb.toString();
-            StringBuilder csb = new StringBuilder();
-            Iterator<String> creditsList = languagePack.getCredits().listIterator();
+            final String fullName = sb.toString();
+            final StringBuilder credits = new StringBuilder();
+            final Iterator<String> creditsList = languagePack.getCredits().listIterator();
+            boolean empty = true;
             while (creditsList.hasNext()) {
-                csb.append(creditsList.next());
+                credits.append(creditsList.next());
                 if (creditsList.hasNext()) {
-                    csb.append(", ");
+                    credits.append(", ");
                 }
+                empty = false;
             }
-            String credits = csb.toString();
-            textRenderer.drawCenteredString(
-                fullName,
-                x + (width / 2),
-                y + 1,
-                0xFFFFFF
-            );
-            textRenderer.drawCenteredString(
-                credits.isEmpty() ? "Unknown Credits" : credits,
-                x + width / 2,
-                y + 12,
-                0x808080
-            );
+            FontHelper.renderCentered(Tessellator.instance, fullName, x + (width / 2), y + 1).setShadow().call(this.mc.font);
+            FontHelper.renderCentered(Tessellator.instance, empty ? "Unknown Credits" : credits, x + width / 2, y + 12).setShadow().setColor(0x808080).call(this.mc.font);
         }
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/OptionsCategory.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/OptionsCategory.java
index 1768e5c0b..2687ef45a 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/OptionsCategory.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/OptionsCategory.java
@@ -2,6 +2,8 @@ package net.minecraft.client.gui.options.components;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ItemElement;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
@@ -83,7 +85,7 @@ public class OptionsCategory
         {
             textColor = 0xFFFFA0;
         }
-        mc.font.drawStringWithShadow((collapsed ? "▷" : "▽"), x, y + PADDING + 10, textColor);
+        FontHelper.render(Tessellator.instance, (this.collapsed ? "▷" : "▽"), x, y + PADDING + 10).setShadow().setColor(textColor).call(mc.font);
 
         int xOffset = 10;
         if (icon != null)
@@ -91,7 +93,7 @@ public class OptionsCategory
             renderItem.render(icon, x + 11, y + PADDING + 5);
             xOffset += 20;
         }
-        mc.font.drawStringWithShadow(i18n.translateKey(translationKey), x + xOffset, y + PADDING + 10, textColor);
+        FontHelper.render(Tessellator.instance, i18n.translateKey(this.translationKey), x + xOffset, y + PADDING + 10).setShadow().setColor(textColor).call(mc.font);
         if (!collapsed) {
             int componentY = TOP_SPACING;
             for (OptionsComponent component : components)
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/SelectedTexturePackListComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/SelectedTexturePackListComponent.java
index d70b966cb..0e8720107 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/SelectedTexturePackListComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/SelectedTexturePackListComponent.java
@@ -2,7 +2,7 @@ package net.minecraft.client.gui.options.components;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.ButtonElement;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texturepack.TexturePack;
 import net.minecraft.client.util.helper.Colors;
@@ -64,7 +64,10 @@ public class SelectedTexturePackListComponent implements OptionsComponent {
     @Override
     public void render(int x, int y, int width, int relativeMouseX, int relativeMouseY) {
         if (selectedPacks.isEmpty()) {
-            mc.font.drawCenteredString(I18n.getInstance().translateKey("gui.options.page.texture_packs.label.no_packs"), x + width / 2, y + 4, 0x5F7F7F7F);
+            FontHelper.renderCentered(Tessellator.instance, I18n.getInstance().translateKey("gui.options.page.texture_packs.label.no_packs"), x + width / 2, y + 4)
+                .setShadow()
+                .setColor(0x5F7F7F7F)
+                .call(mc.font);
         }
         for (TexturePackButton button : selectedPacks) {
             if (button == draggedButton) continue;
@@ -212,7 +215,6 @@ public class SelectedTexturePackListComponent implements OptionsComponent {
 
         public void render(SelectedTexturePackListComponent component, int x, int y, int width, int mouseX, int mouseY) {
             Tessellator tessellator = Tessellator.instance;
-            Font font = mc.font;
 
             setupButton(x, y, width, mouseX, mouseY);
 
@@ -262,21 +264,21 @@ public class SelectedTexturePackListComponent implements OptionsComponent {
 
             if(format == Global.TEXTURE_PACK_FORMAT) {
                 // Correct version
-                font.drawString(texturePack.manifest.getName(),             x + xPos + height + 2, y + yPos + 1, 0xFFFFFF);
-                font.drawString(texturePack.manifest.getDescriptionLine1(), x + xPos + height + 2, y + yPos + 12, 0x808080);
-                font.drawString(texturePack.manifest.getDescriptionLine2(), x + xPos + height + 2, y + yPos + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getName(), x + this.xPos + this.height + 2, y + this.yPos + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine1(), x + this.xPos + this.height + 2, y + this.yPos + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine2(), x + this.xPos + this.height + 2, y + this.yPos + 22).setColor(0x808080).call(mc.font);
             }else if(format == -1) {
                 // Manifest error
-                font.drawString(TextFormatting.RED + texturePack.manifest.getName(), x + xPos + height + 2, y + yPos + 1, 0xFFFFFF);
-                font.drawString(texturePack.manifest.getDescriptionLine1(),          x + xPos + height + 2, y + yPos + 12, 0x808080);
-                font.drawString(texturePack.manifest.getDescriptionLine2(),          x + xPos + height + 2, y + yPos + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, TextFormatting.RED + this.texturePack.manifest.getName(), x + this.xPos + this.height + 2, y + this.yPos + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine1(), x + this.xPos + this.height + 2, y + this.yPos + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, this.texturePack.manifest.getDescriptionLine2(), x + this.xPos + this.height + 2, y + this.yPos + 22).setColor(0x808080).call(mc.font);
                 rgbVersion = Colors.allChatColors[TextFormatting.RED.id].getARGB();
             }else {
                 // Wrong texture pack version
                 I18n i18n = I18n.getInstance();
-                font.drawString(TextFormatting.RED + texturePack.manifest.getName(),                            x + xPos + height + 2, y + yPos + 1, 0xFFFFFF);
-                font.drawString(i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.1"),  x + xPos + height + 2, y + yPos + 12, 0x808080);
-                font.drawString(i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.2"),  x + xPos + height + 2, y + yPos + 22, 0x808080);
+                FontHelper.render(Tessellator.instance, TextFormatting.RED + this.texturePack.manifest.getName(), x + this.xPos + this.height + 2, y + this.yPos + 1).call(mc.font);
+                FontHelper.render(Tessellator.instance, i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.1"), x + this.xPos + this.height + 2, y + this.yPos + 12).setColor(0x808080).call(mc.font);
+                FontHelper.render(Tessellator.instance, i18n.translateKey("gui.options.page.texture_packs.label.outdated_pack.2"), x + this.xPos + this.height + 2, y + this.yPos + 22).setColor(0x808080).call(mc.font);
                 rgbVersion = Colors.allChatColors[TextFormatting.RED.id].getARGB();
             }
 
@@ -286,8 +288,8 @@ public class SelectedTexturePackListComponent implements OptionsComponent {
             }
 
             String version = texturePack.manifest.getPackVersion();
-            int versionWidth = font.getStringWidth(version);
-            font.drawString(texturePack.manifest.getPackVersion(), x + xPos + width - versionWidth - 2, y + yPos + 1, rgbVersion);
+            int versionWidth = mc.font.stringWidth(version);
+            FontHelper.render(Tessellator.instance, this.texturePack.manifest.getPackVersion(), x + this.xPos + width - versionWidth - 2, y + this.yPos + 1).setColor(rgbVersion).call(mc.font);
         }
         public void setupButton(int x, int y, int width, int mouseX, int mouseY){
             button.setX(x + xPos + width - button.width - 1);
diff --git a/game/client/src/main/java/net/minecraft/client/gui/options/components/TooltipPickerComponent.java b/game/client/src/main/java/net/minecraft/client/gui/options/components/TooltipPickerComponent.java
index 2aa7d2655..984d1d2a5 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/options/components/TooltipPickerComponent.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/options/components/TooltipPickerComponent.java
@@ -14,6 +14,7 @@ public class TooltipPickerComponent
         super(option);
 
         this.tooltip = new TooltipElement(mc);
+        this.slider.renderText = false;
     }
 
     @Override
@@ -22,9 +23,10 @@ public class TooltipPickerComponent
 
         final int padding = 3;
         final int yOffset = 0;
-        final int stringWidth = mc.font.getStringWidth(this.option.getDisplayStringValue()) + padding * 2;
+        final int stringWidth = mc.font.stringWidth(this.option.getDisplayStringValue());
+        final int stringHeight = mc.font.fontHeight();
         GL11.glColor4f(1, 1, 1, 1);
-        this.tooltip.render(this.option.getDisplayStringValue(), x + relativeButtonX + buttonWidth / 2 - stringWidth / 2, y + relativeButtonY + 3 + yOffset, 0, 0);
+        this.tooltip.render(this.option.getDisplayStringValue(), x + relativeButtonX + buttonWidth/2 - stringWidth/2, y + relativeButtonY + buttonHeight/2 - stringHeight/2, 0, 0, -1, -1, false);
 
         if (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/options/data/OptionsPages.java b/game/client/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index c2392c95d..d520763ea 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
@@ -4,6 +4,7 @@ import net.betterthanadventure.utils.DataDumper;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.enums.EnumGPUVendor;
 import net.minecraft.client.gui.ScreenControllerSetup;
+import net.minecraft.client.gui.ScreenFontTest;
 import net.minecraft.client.gui.ScreenHudDesigner;
 import net.minecraft.client.gui.ScreenSoundTest;
 import net.minecraft.client.gui.ScreenTextureViewer;
@@ -359,6 +360,7 @@ public abstract class OptionsPages
                     new Thread(() -> SeedViewerMain.main(new String[0])).start();
                     Global.accessor = mc;
                 }))
+                .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.font_tester", () -> mc.displayScreen(new ScreenFontTest(mc.currentScreen))))
                 .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.datadumper", () ->{
                     DataDumper.main(new String[0]);
                     FileOpener.open(new File(mc.getMinecraftDir(), "infodump"));
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 1c6e6ff62..65c256665 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
@@ -107,7 +107,7 @@ public class ScreenPaged
                 textColor = 0xFFFFFFA0;
             }
             renderItem.render(page.getIcon(), x, y2 + (PAGE_BUTTON_HEIGHT / 2) - 9);
-            mc.font.drawStringWithShadow(translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
+            drawStringShadow(this.fontRenderer, translated, x + 19, y2 + (PAGE_BUTTON_HEIGHT / 2) - 4, textColor);
             y2 += PAGE_BUTTON_HEIGHT;
         }
     }
@@ -257,7 +257,7 @@ public class ScreenPaged
 
         overlayBackground(leftWidth, leftWidth + SEPARATOR_WIDTH, top, bottom);
 
-        drawStringCentered(font, i18n.translateKey(titleTranslationKey), width / 2, 5, 0xffffff);
+        drawStringCenteredShadow(fontRenderer, i18n.translateKey(titleTranslationKey), width / 2, 5, 0xffffff);
 
         drawRightPanelScrollBar(mx, my);
         drawLeftPanelScrollBar(mx, my);
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 bd8c6f156..362e4629f 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
@@ -1,19 +1,20 @@
 package net.minecraft.client.gui.popup;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
+import net.minecraft.client.render.tessellator.Tessellator;
 
 public class LabelComponent
     extends PopupComponent
 {
-    private final Font fr;
+    private final FontRenderer fontRenderer;
     private final String text;
     private final int color;
 
-    public LabelComponent(int width, String text, int color)
-    {
+    public LabelComponent(final int width, final String text, final int color) {
         super(width);
-        this.fr = Minecraft.getMinecraft().font;
+        this.fontRenderer = Minecraft.getMinecraft().font;
         this.text = text;
         this.color = color;
     }
@@ -25,10 +26,8 @@ public class LabelComponent
     }
 
     @Override
-    public void render(int x, int y, int mouseX, int mouseY)
-    {
-        int middle = (x - PopupScreen.HORIZONTAL_MARGIN) + getWidth() / 2;
-
-        fr.drawCenteredString(text, middle, y, color);
+    public void render(final int x, final int y, final int mouseX, final int mouseY) {
+        final int middle = (x - PopupScreen.HORIZONTAL_MARGIN) + getWidth() / 2;
+        FontHelper.renderCentered(Tessellator.instance, this.text, middle, y).setShadow().setColor(this.color).call(this.fontRenderer);
     }
 }
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 d34d7efd1..52d0dac0c 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
@@ -2,7 +2,9 @@ package net.minecraft.client.gui.popup;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.render.Scissor;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.net.command.TextFormatting;
 import net.minecraft.core.util.helper.MathHelper;
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
@@ -14,6 +16,7 @@ import java.util.List;
 public class MessageBoxComponent
     extends PopupComponent
 {
+    private static final String FORMAT_REGEX = "[" + TextFormatting.FORMAT_CHARS + "]";
     private final Minecraft minecraft;
     private float scrollAmount = 0;
     private final List<String> lines = new ArrayList<>();
@@ -68,7 +71,7 @@ public class MessageBoxComponent
                 if (word.contains("§")) {
                     if (word.indexOf('§') < word.length() - 1) {
                         String format = String.valueOf(word.charAt(word.indexOf('§') + 1));
-                        if (format.matches("[0123456789abcdefklmnor]")) { //if matches any valid text format
+                        if (format.matches(FORMAT_REGEX)) { //if matches any valid text format
                             currentFormat = "§" + format;
                         }
                     }
@@ -124,7 +127,7 @@ public class MessageBoxComponent
         // Draw lines
         for (int i = 0; i < lines.size(); i++)
         {
-            minecraft.font.drawStringWithShadow(lines.get(i),x + 4,(y + 4) + (i * 12) - getScrollPixels(),0xFFFFFFFF);
+            FontHelper.render(Tessellator.instance, lines.get(i),x + 4,(y + 4) + (i * 12) - getScrollPixels()).setShadow().call(this.minecraft.font);
         }
 
         Scissor.disable();
diff --git a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
index eaafc2209..d9313b0ba 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/toasts/GuiElementToastsHud.java
@@ -90,9 +90,9 @@ public class GuiElementToastsHud extends Gui {
             String s = I18n.getInstance().translateKeyAndFormat("gui.achievement.label.unlicensed.1", Global.VERSION);
             String s1 = I18n.getInstance().translateKey("gui.achievement.label.unlicensed.2");
             String s2 = I18n.getInstance().translateKey("gui.achievement.label.unlicensed.3");
-            mc.font.drawStringWithShadow(s, 2, 2, 0xffffff);
-            mc.font.drawStringWithShadow(s1, 2, 11, 0xffffff);
-            mc.font.drawStringWithShadow(s2, 2, 20, 0xffffff);
+            drawStringShadow(mc.font, s, 2, 2, 0xffffff);
+            drawStringShadow(mc.font, s1, 2, 11, 0xffffff);
+            drawStringShadow(mc.font, s2, 2, 20, 0xffffff);
             GL11.glDepthMask(true);
             GL11.glEnable(GL11.GL_DEPTH_TEST);
         }
@@ -166,10 +166,10 @@ public class GuiElementToastsHud extends Gui {
 
         drawGuiIcon(x, y, TOAST_WIDTH, TOAST_HEIGHT, TextureRegistry.getTexture(toast.getTexture(duration)));
         if(toast.messageOnly(duration)) {
-            mc.font.drawStringIntoConstrainedBlock(toast.getMessage(duration), x + 30, y + 7, 120, toast.descriptionColor(duration));
+            drawStringConstrained(mc.font, toast.getMessage(duration), x + 30, y + 7, 120, toast.descriptionColor(duration));
         } else {
-            mc.font.drawString(toast.getTitle(duration), x + 30, y + 7, toast.nameColor(duration));
-            mc.font.drawString(toast.getMessage(duration), x + 30, y + 18, toast.descriptionColor(duration));
+            drawStringNoShadow(mc.font, toast.getTitle(duration), x + 30, y + 7, toast.nameColor(duration));
+            drawStringNoShadow(mc.font, toast.getMessage(duration), x + 30, y + 18, toast.descriptionColor(duration));
         }
 
         GL11.glDepthMask(true);
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 af733e962..322e568c7 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
@@ -275,8 +275,6 @@ public class GameSettings {
 	public GameSettings(Minecraft minecraft, File file) {
 		mc = minecraft;
 		optionsFile = new File(file, "options.txt");
-		loadOptions();
-		saveOptions();
 
 		debugsKeys.add(keyShowShortcuts);
 		debugsKeys.add(keyReload);
@@ -292,6 +290,11 @@ public class GameSettings {
 		debugsKeys.add(keyReloadChunks);
 		debugsKeys.add(keySmoothLighting);
 	}
+
+	public void init() {
+		loadOptions();
+		saveOptions();
+	}
 	
 	public String getDisplayString(Option<?> option) {
 		if (option == null) return "";
diff --git a/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
index e2298fdac..1b95542cc 100644
--- a/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/EntityRenderDispatcher.java
@@ -4,6 +4,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import net.minecraft.client.render.entity.*;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.model.*;
 import net.minecraft.core.entity.EntityItem;
 import net.minecraft.core.entity.EntityLightning;
@@ -105,12 +106,12 @@ public class EntityRenderDispatcher
         return getRenderer(entity.getClass());
     }
 
-    public void cacheActiveRenderInfo(World world, TextureManager textureManager, Font font, ICamera camera, GameSettings gameSettings, float partialTick)
+    public void cacheActiveRenderInfo(World world, TextureManager textureManager, FontRenderer fontRenderer, ICamera camera, GameSettings gameSettings, float partialTick)
     {
         this.world = world;
         this.textureManager = textureManager;
         this.gameSettings = gameSettings;
-        this.font = font;
+        this.fontRenderer = fontRenderer;
         this.camera = camera;
         viewLerpYaw = (float) camera.getYRot(partialTick);
         viewLerpPitch = (float) camera.getXRot(partialTick);
@@ -184,14 +185,14 @@ public class EntityRenderDispatcher
         return dx * dx + dy * dy + dz * dz;
     }
 
-    public Font getFont()
+    public FontRenderer getFont()
     {
-        return font;
+        return this.fontRenderer;
     }
 
     private final Map<Class<?>, EntityRenderer<?>> renderers;
     public static EntityRenderDispatcher instance = new EntityRenderDispatcher();
-    private Font font;
+    private FontRenderer fontRenderer;
     public static double renderPosX;
     public static double renderPosY;
     public static double renderPosZ;
diff --git a/game/client/src/main/java/net/minecraft/client/render/Font.java b/game/client/src/main/java/net/minecraft/client/render/Font.java
deleted file mode 100644
index 45af56f0d..000000000
--- a/game/client/src/main/java/net/minecraft/client/render/Font.java
+++ /dev/null
@@ -1,833 +0,0 @@
-package net.minecraft.client.render;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.core.lang.text.Text;
-import net.minecraft.client.option.GameSettings;
-import net.minecraft.client.render.tessellator.Tessellator;
-import net.minecraft.client.render.texture.Texture;
-import net.minecraft.core.net.command.TextFormatting;
-import net.minecraft.core.util.helper.ChatAllowedCharacters;
-import net.minecraft.core.util.helper.Color;
-import net.minecraft.client.util.helper.Colors;
-import org.lwjgl.opengl.GL11;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.Bidi;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.regex.Pattern;
-
-public class Font {
-    private static final Pattern FORMATTING_CODE_REGEX = Pattern.compile("(?i)\\u00A7[0-9A-FK-OR]");
-    private static final int MONOSPACE_WIDTH = 10;
-
-    private final boolean monospace;
-    private final GameSettings gameSettings;
-    private final Minecraft mc;
-    private final byte[] charWidth;
-    public int fontTextureName;
-    private final int[] fontTextureNames;
-    public int fontHeight;
-    public Random random;
-    private final byte[] glyphWidth;
-    private final int[] glyphTextureNames;
-    private final int[] colorCode;
-    private int boundTextureName;
-    private final TextureManager textureManager;
-    private float posX;
-    private float posY;
-    private boolean bidiFlag;
-    private float red;
-    private float blue;
-    private float green;
-    private float alpha;
-    private int textColor;
-    private boolean obfuscatedStyle;
-    private boolean boldStyle;
-    private boolean italicStyle;
-    private boolean underlineStyle;
-    private boolean strikethroughStyle;
-
-    public Font(Minecraft minecraft, GameSettings gameSettings, TextureManager textureManager) {
-        this(minecraft, gameSettings, textureManager, false);
-    }
-
-    public Font(Minecraft minecraft, GameSettings gameSettings, TextureManager textureManager, boolean monospace) {
-        this.mc = minecraft;
-        this.gameSettings = gameSettings;
-        this.charWidth = new byte[65536];
-        this.fontTextureName = 0;
-        this.fontTextureNames = new int[256];
-        this.fontHeight = 9;
-        this.random = new Random();
-        this.glyphWidth = new byte[65536];
-        this.glyphTextureNames = new int[256];
-        this.colorCode = new int[32];
-        this.obfuscatedStyle = false;
-        this.boldStyle = false;
-        this.italicStyle = false;
-        this.underlineStyle = false;
-        this.strikethroughStyle = false;
-        this.textureManager = textureManager;
-        this.monospace = monospace;
-
-        if (monospace) {
-            Arrays.fill(this.glyphWidth, (byte) MONOSPACE_WIDTH);
-            Arrays.fill(this.charWidth, (byte) MONOSPACE_WIDTH);
-        } else {
-            try (InputStream glyphStream = mc.texturePackList.getResourceAsStream("/font/glyph_sizes.bin");
-                 InputStream glyphStreamDefault = mc.texturePackList.getResourceAsStream("/font/glyph_sizes_default.bin")) {
-                glyphStream.read(this.glyphWidth);
-                glyphStreamDefault.read(this.charWidth);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        for (int i = 0; i < 32; ++i) {
-            Color color = Colors.allChatColors[i & 0xF];
-
-            int r = color.getRed();
-            int g = color.getGreen();
-            int b = color.getBlue();
-
-            if(i >= 16) {
-                r /= 4;
-                g /= 4;
-                b /= 4;
-            }
-
-            this.colorCode[i] = (r & 255) << 16 | (g & 255) << 8 | b & 255;
-        }
-    }
-
-    private float renderCharAtPos(int formatCode, char c, boolean italic) {
-        float charWidth;
-        if (c == 32 && !this.monospace)
-        {
-            charWidth = 4.0F;
-        }
-        else if (DEFAULT_BLACKLIST.contains(c))
-        {
-            charWidth = this.renderUnicodeChar(c, italic);
-        }
-        else if (formatCode > 0 && !gameSettings.forceUnicodeFont.value)
-        {
-            charWidth = this.renderDefaultChar((char)formatCode, italic);
-        }
-        else
-        {
-            charWidth = this.renderUnicodeChar(c, italic);
-        }
-
-        return charWidth;
-    }
-
-    private boolean loadDefaultTexture(int id) {
-        boolean success = true;
-
-        String fontPath;
-        if (this.monospace) {
-            fontPath = String.format("/font/mono_%02X.png", id);
-        } else {
-            fontPath = String.format("/font/font_%02X.png", id);
-        }
-        String glyphPath = String.format("/font/glyph_%02X.png", id);
-
-        Texture fontTexture = this.textureManager.loadTextureNoDefault(fontPath);
-        if (fontTexture == null && this.monospace) {
-            fontTexture = this.textureManager.loadTextureNoDefault(String.format("/font/font_%02X.png", id));
-        }
-        if (fontTexture == null) {
-            fontTexture = this.textureManager.loadTextureNoDefault(glyphPath);
-        }
-        if (fontTexture == null) {
-            throw new RuntimeException("Failed to load texture from '" + fontPath + "' or '" + glyphPath + "'!");
-        }
-
-        this.fontTextureNames[id] = fontTexture.id();
-        this.boundTextureName = this.fontTextureNames[id];
-        return success;
-    }
-
-    private float renderDefaultChar(char c, boolean italic) {
-        if (this.charWidth[c] == 0 && this.glyphWidth[c] == 0) {
-            return 0.0F;
-        } else {
-            int charWrapped = c / 256;
-            boolean isFontImage = true;
-            if (this.fontTextureNames[charWrapped] == 0) {
-                isFontImage = this.loadDefaultTexture(charWrapped);
-            }
-
-            if (isFontImage) {
-                if (this.boundTextureName != this.fontTextureNames[charWrapped]) {
-                    GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.fontTextureNames[charWrapped]);
-                    this.boundTextureName = this.fontTextureNames[charWrapped];
-                }
-            } else {
-                if (this.boundTextureName != this.glyphTextureNames[charWrapped]) {
-                    GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.glyphTextureNames[charWrapped]);
-                    this.boundTextureName = this.glyphTextureNames[charWrapped];
-                }
-            }
-
-            int upper = isFontImage ? this.charWidth[c] >> 4 : this.glyphWidth[c] >> 4;
-            int lower = isFontImage ? this.charWidth[c] & 0x0F : this.glyphWidth[c] & 0x0F;
-            float fUpper = (float)upper;
-            float fLower = (float)(lower + 1);
-            float x = (float)(c % 16 * 16) + fUpper;
-            float y = (float)((c & 255) / 16 * 16);
-            float var10 = fLower - fUpper - 0.02F;
-            float italicOffset = italic ? 1.0F : 0.0F;
-            GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
-            GL11.glTexCoord2f(x / 256.0F, y / 256.0F);
-            GL11.glVertex3f(this.posX + italicOffset, this.posY, 0.0F);
-            GL11.glTexCoord2f(x / 256.0F, (y + 15.98F) / 256.0F);
-            GL11.glVertex3f(this.posX - italicOffset, this.posY + 7.99F, 0.0F);
-            GL11.glTexCoord2f((x + var10) / 256.0F, y / 256.0F);
-            GL11.glVertex3f(this.posX + var10 / 2.0F + italicOffset, this.posY, 0.0F);
-            GL11.glTexCoord2f((x + var10) / 256.0F, (y + 15.98F) / 256.0F);
-            GL11.glVertex3f(this.posX + var10 / 2.0F - italicOffset, this.posY + 7.99F, 0.0F);
-            GL11.glEnd();
-            return (fLower - fUpper) / 2.0F + 1.0F;
-        }
-    }
-
-    private void loadGlyphTexture(int id) {
-        String glyphPath = String.format("/font/glyph_%02X.png", id);
-
-        BufferedImage glyphTexture;
-        try {
-            glyphTexture = ImageIO.read(mc.texturePackList.getResourceAsStream(glyphPath));
-        } catch (IOException var5) {
-            throw new RuntimeException(var5);
-        }
-
-        this.glyphTextureNames[id] = this.textureManager.loadBufferedTexture(glyphTexture).id();
-        this.boundTextureName = this.glyphTextureNames[id];
-    }
-
-    private float renderUnicodeChar(char c, boolean par2) {
-        if (this.glyphWidth[c] == 0) {
-            return 0.0F;
-        } else {
-            int charWrapped = c / 256;
-            if (this.glyphTextureNames[charWrapped] == 0) {
-                this.loadGlyphTexture(charWrapped);
-            }
-
-            if (this.boundTextureName != this.glyphTextureNames[charWrapped]) {
-                GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.glyphTextureNames[charWrapped]);
-                this.boundTextureName = this.glyphTextureNames[charWrapped];
-            }
-
-            int var4 = this.glyphWidth[c] >>> 4;
-            int var5 = this.glyphWidth[c] & 15;
-            float var6 = (float)var4;
-            float var7 = (float)(var5 + 1);
-            float var8 = (float)(c % 16 * 16) + var6;
-            float var9 = (float)((c & 255) / 16 * 16);
-            float var10 = var7 - var6 - 0.02F;
-            float var11 = par2 ? 1.0F : 0.0F;
-            GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
-            GL11.glTexCoord2f(var8 / 256.0F, var9 / 256.0F);
-            GL11.glVertex3f(this.posX + var11, this.posY, 0.0F);
-            GL11.glTexCoord2f(var8 / 256.0F, (var9 + 15.98F) / 256.0F);
-            GL11.glVertex3f(this.posX - var11, this.posY + 7.99F, 0.0F);
-            GL11.glTexCoord2f((var8 + var10) / 256.0F, var9 / 256.0F);
-            GL11.glVertex3f(this.posX + var10 / 2.0F + var11, this.posY, 0.0F);
-            GL11.glTexCoord2f((var8 + var10) / 256.0F, (var9 + 15.98F) / 256.0F);
-            GL11.glVertex3f(this.posX + var10 / 2.0F - var11, this.posY + 7.99F, 0.0F);
-            GL11.glEnd();
-            return (var7 - var6) / 2.0F + 1.0F;
-        }
-    }
-
-    public void drawTextWithShadow(Text text, int x, int y, int color) {
-        this.drawText(text, x, y, color, true);
-    }
-
-    public void drawText(Text text, int x, int y, int color) {
-        this.drawText(text, x, y, color, false);
-    }
-
-    public int drawText(Text text, int x, int y, int color, boolean shadow) {
-        return drawString(text.toString(), x, y, color, shadow);
-    }
-
-    public void drawStringWithShadow(String text, int x, int y, int color) {
-        this.drawString(text, x, y, color, true);
-    }
-
-    public void drawString(String text, int x, int y, int color) {
-        this.drawString(text, x, y, color, false);
-    }
-
-    public int drawString(String text, int x, int y, int color, boolean shadow) {
-        if (text != null) {
-            StringBuilder sb = new StringBuilder();
-            boolean modified = false;
-            for (char c : text.toCharArray()) {
-                switch (c) {
-                    case '（':
-                        sb.append(" (");
-                        modified = true;
-                        break;
-                    case '）':
-                        sb.append(") ");
-                        modified = true;
-                        break;
-                    default:
-                        sb.append(c);
-                        break;
-                }
-            }
-            if (modified) {
-                text = sb.toString();
-            }
-        }
-        this.resetStyles();
-        if(this.bidiFlag) {
-            text = this.bidiReorder(text);
-        }
-
-        int var6;
-        if (shadow) {
-            var6 = this.renderStringInternal(text, x + 1, y + 1, color, true);
-            var6 = Math.max(var6, this.renderStringInternal(text, x, y, color, false));
-        } else {
-            var6 = this.renderStringInternal(text, x, y, color, false);
-        }
-
-        return var6;
-    }
-
-    private String bidiReorder(String par1Str) {
-        if(par1Str != null && Bidi.requiresBidi(par1Str.toCharArray(), 0, par1Str.length())) {
-            Bidi var2 = new Bidi(par1Str, -2);
-            byte[] var3 = new byte[var2.getRunCount()];
-            String[] var4 = new String[var3.length];
-
-            int var7;
-            for(int var11 = 0; var11 < var3.length; ++var11) {
-                int var12 = var2.getRunStart(var11);
-                var7 = var2.getRunLimit(var11);
-                int var13 = var2.getRunLevel(var11);
-                String var14 = par1Str.substring(var12, var7);
-                var3[var11] = (byte)var13;
-                var4[var11] = var14;
-            }
-
-            String[] var111 = var4.clone();
-            Bidi.reorderVisually(var3, 0, var4, 0, var3.length);
-            StringBuilder var121 = new StringBuilder();
-            var7 = 0;
-
-            while (var7 < var4.length) {
-                byte var131 = var3[var7];
-                int var141 = 0;
-
-                while(true) {
-                    if(var141 < var111.length) {
-                        if(!var111[var141].equals(var4[var7])) {
-                            ++var141;
-                            continue;
-                        }
-
-                        var131 = var3[var141];
-                    }
-
-                    if((var131 & 1) == 0) {
-                        var121.append(var4[var7]);
-                    } else {
-                        for(var141 = var4[var7].length() - 1; var141 >= 0; --var141) {
-                            char var10 = var4[var7].charAt(var141);
-                            if(var10 == 40) {
-                                var10 = 41;
-                            } else if(var10 == 41) {
-                                var10 = 40;
-                            }
-
-                            var121.append(var10);
-                        }
-                    }
-
-                    ++var7;
-                    break;
-                }
-            }
-
-            return var121.toString();
-        } else {
-            return par1Str;
-        }
-    }
-
-    private void resetStyles() {
-        this.obfuscatedStyle = false;
-        this.boldStyle = false;
-        this.italicStyle = false;
-        this.underlineStyle = false;
-        this.strikethroughStyle = false;
-    }
-
-    private void renderStringAtPos(String text, boolean flag) {
-        for(int i = 0; i < text.length(); ++i) {
-            char c = text.charAt(i);
-            int fontIndex;
-            int var6;
-            if (c == '\247' && i + 1 < text.length()) {
-                char colorSymbol = text.toLowerCase().charAt(i + 1);
-                if (colorSymbol == '<'){ // Full rgb color code
-                    int offAmount = 1;
-                    int j = i + 2;
-                    StringBuilder colorValue = new StringBuilder();
-                    boolean ended = false;
-                    while (j < text.length()){
-                        offAmount++;
-                        if (text.charAt(j) == '>'){
-                            ended = true;
-                            break;
-                        }
-                        colorValue.append(text.charAt(j));
-                        j++;
-                    }
-
-                    if (ended){
-                        i += offAmount;
-
-                        int colorInt = 0xFFFFFF;
-                        try {
-                            colorInt = Integer.decode("0x" + colorValue.toString().toLowerCase());
-                        } catch (NumberFormatException ignored){
-                        }
-
-                        float r = (float)(colorInt >> 16) / 255.0F;
-                        float g = (float)(colorInt >> 8 & 0xff) / 255.0F;
-                        float b = (float)(colorInt & 0xff) / 255.0F;
-
-                        this.obfuscatedStyle = false;
-                        this.boldStyle = false;
-                        this.strikethroughStyle = false;
-                        this.underlineStyle = false;
-                        this.italicStyle = false;
-
-                        if (flag){
-                            r /= 4;
-                            g /= 4;
-                            b /= 4;
-                        }
-
-                        this.textColor = colorInt;
-                        GL11.glColor4f(r, g, b, this.alpha);
-                        continue;
-                    }
-                } else {
-                    fontIndex = "0123456789abcdefklmnor".indexOf(colorSymbol);
-                    if (fontIndex != -1){
-                        if (fontIndex < 16) {
-                            this.obfuscatedStyle = false;
-                            this.boldStyle = false;
-                            this.strikethroughStyle = false;
-                            this.underlineStyle = false;
-                            this.italicStyle = false;
-                            if (fontIndex < 0) {
-                                fontIndex = 15;
-                            }
-
-                            if (flag) {
-                                fontIndex += 16;
-                            }
-
-                            var6 = this.colorCode[fontIndex];
-                            this.textColor = var6;
-                            GL11.glColor4f((float)(var6 >> 16) / 255.0F, (float)(var6 >> 8 & 255) / 255.0F, (float)(var6 & 255) / 255.0F, this.alpha);
-                        } else if (fontIndex == 16) {
-                            this.obfuscatedStyle = true;
-                        } else if (fontIndex == 17) {
-                            this.boldStyle = true;
-                        } else if (fontIndex == 18) {
-                            this.strikethroughStyle = true;
-                        } else if (fontIndex == 19) {
-                            this.underlineStyle = true;
-                        } else if (fontIndex == 20) {
-                            this.italicStyle = true;
-                        } else if (fontIndex == 21) {
-                            this.obfuscatedStyle = false;
-                            this.boldStyle = false;
-                            this.strikethroughStyle = false;
-                            this.underlineStyle = false;
-                            this.italicStyle = false;
-                            GL11.glColor4f(this.red, this.blue, this.green, this.alpha);
-                        }
-                        i++;
-                        continue;
-                    }
-                }
-            }
-            c = text.charAt(i);
-            fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
-            if (this.obfuscatedStyle && fontIndex > 0) {
-                do {
-                    var6 = this.random.nextInt(ChatAllowedCharacters.ALLOWED_CHARACTERS.length());
-                } while (this.charWidth[fontIndex + 32] != this.charWidth[var6 + 32]);
-
-                fontIndex = var6;
-            }
-
-            float var9 = this.renderCharAtPos(fontIndex, c, this.italicStyle);
-            if (this.boldStyle) {
-                ++this.posX;
-                this.renderCharAtPos(fontIndex, c, this.italicStyle);
-                --this.posX;
-                ++var9;
-            }
-
-            Tessellator var7;
-            if(this.strikethroughStyle) {
-                var7 = Tessellator.instance;
-                GL11.glDisable(GL11.GL_TEXTURE_2D);
-                var7.startDrawingQuads();
-                var7.addVertex(this.posX, this.posY + (float)(this.fontHeight / 2), 0.0D);
-                var7.addVertex(this.posX + var9, this.posY + (float)(this.fontHeight / 2), 0.0D);
-                var7.addVertex(this.posX + var9, this.posY + (float)(this.fontHeight / 2) - 1.0F, 0.0D);
-                var7.addVertex(this.posX, this.posY + (float)(this.fontHeight / 2) - 1.0F, 0.0D);
-                var7.draw();
-                GL11.glEnable(GL11.GL_TEXTURE_2D);
-            }
-
-            if(this.underlineStyle) {
-                var7 = Tessellator.instance;
-                GL11.glDisable(GL11.GL_TEXTURE_2D);
-                var7.startDrawingQuads();
-                int var8 = this.underlineStyle ? -1 : 0;
-                var7.addVertex(this.posX + (float)var8, this.posY + (float)this.fontHeight, 0.0D);
-                var7.addVertex(this.posX + var9, this.posY + (float)this.fontHeight, 0.0D);
-                var7.addVertex(this.posX + var9, this.posY + (float)this.fontHeight - 1.0F, 0.0D);
-                var7.addVertex(this.posX + (float)var8, this.posY + (float)this.fontHeight - 1.0F, 0.0D);
-                var7.draw();
-                GL11.glEnable(GL11.GL_TEXTURE_2D);
-            }
-
-            this.posX += (float)((int)var9);
-        }
-
-    }
-
-    private int renderStringAligned(String s, int x, int y, int maxWidth, int argb, boolean isShadow) {
-        if(this.bidiFlag) {
-            s = this.bidiReorder(s);
-            int width = this.getStringWidth(s);
-            x = x + maxWidth - width;
-        }
-
-        return this.renderStringInternal(s, x, y, argb, isShadow);
-    }
-
-    public void renderString(String par1Str, int par2, int par3, int par4, boolean par5) {
-        this.renderStringInternal(par1Str, par2, par3, par4, par5);
-    }
-
-    private int renderStringInternal(String text, int x, int y, int color, boolean isShadow) {
-        if (text == null) {
-            return 0;
-        } else {
-            this.boundTextureName = 0;
-            if((color & 0xFF000000) == 0) {
-                color |= 0xFF000000;
-            }
-
-            if(isShadow) {
-                color = (color & 0xFCFCFC) >> 2 | color & 0xFF000000;
-            }
-
-            this.red = (float)(color >> 16 & 255) / 255.0F;
-            this.blue = (float)(color >> 8 & 255) / 255.0F;
-            this.green = (float)(color & 255) / 255.0F;
-            this.alpha = (float)(color >> 24 & 255) / 255.0F;
-            GL11.glColor4f(this.red, this.blue, this.green, this.alpha);
-            this.posX = (float)x;
-            this.posY = (float)y;
-            this.renderStringAtPos(text, isShadow);
-            return (int)this.posX;
-        }
-    }
-
-    public int getTextWidth(Text text) {
-        if (text == null) {
-            return 0;
-        }
-        return getStringWidth(text.toString());
-    }
-
-    public int getStringWidth(String string) {
-        if(string == null) {
-            return 0;
-        } else {
-            string = TextFormatting.removeAllFormatting(string);
-            int stringWidth = 0;
-            boolean addSpacerPixel = false;
-
-            for(int i = 0; i < string.length(); i++) {
-                char c = string.charAt(i);
-                int charWidth = this.getCharWidth(c);
-                if(charWidth < 0 && i < string.length() - 1) {
-                    ++i;
-                    c = string.charAt(i);
-                    if(c != 'l' && c != 'L') {
-                        if(c == 'r' || c == 'R') {
-                            addSpacerPixel = false;
-                        }
-                    } else {
-                        addSpacerPixel = true;
-                    }
-
-                    charWidth = 0;
-                }
-
-                stringWidth += charWidth;
-                if(addSpacerPixel) {
-                    stringWidth++;
-                }
-            }
-
-            return stringWidth;
-        }
-    }
-
-    public int getCharWidth(char c) {
-        if (this.monospace) {
-            return MONOSPACE_WIDTH / 2 + 1;
-        }
-        /*if (c == '§') {
-            return -1;
-        } else */if (c == ' ') {
-            return 4;
-        } else {
-            int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
-            if (fontIndex >= 0 && !DEFAULT_BLACKLIST.contains(c) && !gameSettings.forceUnicodeFont.value) {
-                int upper = this.charWidth[fontIndex] >> 4;
-                int lower = this.charWidth[fontIndex] & 0x0F;
-                float fUpper = (float)upper;
-                float fLower = (float)(lower + 1);
-
-                return (int)((fLower - fUpper) / 2.0F + 1.0F);
-            } else if (this.glyphWidth[c] != 0) {
-                int upper = this.glyphWidth[c] >> 4;
-                int lower = this.glyphWidth[c] & 0x0F;
-                if (lower > 7) {
-                    lower = 15;
-                    upper = 0;
-                }
-
-                ++lower;
-                return (lower - upper) / 2 + 1;
-            } else {
-                return 0;
-            }
-        }
-    }
-
-    public String trimStringToWidth(String s, int maxWidth) {
-        return this.trimStringToWidth(s, maxWidth, false);
-    }
-
-    public String trimStringToWidth(String s, int maxWidth, boolean par3) {
-        StringBuilder var4 = new StringBuilder();
-        int var5 = 0;
-        int var6 = par3 ? s.length() - 1 : 0;
-        int var7 = par3 ? -1 : 1;
-        boolean var8 = false;
-        boolean var9 = false;
-
-        for(int var10 = var6; var10 >= 0 && var10 < s.length() && var5 < maxWidth; var10 += var7) {
-            char var11 = s.charAt(var10);
-            int var12 = this.getCharWidth(var11);
-            if(var8) {
-                var8 = false;
-                if(var11 != 108 && var11 != 76) {
-                    if(var11 == 114 || var11 == 82) {
-                        var9 = false;
-                    }
-                } else {
-                    var9 = true;
-                }
-            } else if(var12 < 0) {
-                var8 = true;
-            } else {
-                var5 += var12;
-                if(var9) {
-                    ++var5;
-                }
-            }
-
-            if(var5 > maxWidth) {
-                break;
-            }
-
-            if(par3) {
-                var4.insert(0, var11);
-            } else {
-                var4.append(var11);
-            }
-        }
-
-        return var4.toString();
-    }
-
-    private String trimStringNewline(String s) {
-        while(s != null && s.endsWith("\n")) {
-            s = s.substring(0, s.length() - 1);
-        }
-
-        return s;
-    }
-
-    public void drawStringIntoConstrainedBlock(String s, int x, int y, int maxWidth, int argb) {
-        this.drawStringIntoConstrainedBlock(s, x, y, maxWidth, argb, false);
-    }
-
-    private void renderSplitString(String s, int x, int y, int maxWidth, boolean isShadow) {
-        List<String> lines = this.listFormattedStringToWidth(s, maxWidth);
-
-        for (String line : lines) {
-            this.renderStringAligned(line, x, y, maxWidth, this.textColor, isShadow);
-            y += this.fontHeight;
-        }
-
-    }
-
-    public int getHeightOfConstrainedString(String s, int maxWidth) {
-        return this.fontHeight * this.listFormattedStringToWidth(s, maxWidth).size();
-    }
-
-    public void setBidiFlag(boolean par1) {
-        this.bidiFlag = par1;
-    }
-
-    public List<String> listFormattedStringToWidth(String s, int maxWidth) {
-        return Arrays.asList(this.wrapFormattedStringToWidth(s, maxWidth).split("\n"));
-    }
-
-    public String wrapFormattedStringToWidth(String s, int maxWidth) {
-        int var3 = this.sizeStringToWidth(s, maxWidth);
-        if(s.length() <= var3) {
-            return s;
-        } else {
-            String var4 = s.substring(0, var3);
-            char var5 = s.charAt(var3);
-            boolean var6 = (var5 == 32 && !this.monospace) || var5 == 10;
-            String var7 = getFormatFromString(var4) + s.substring(var3 + (var6 ? 1 : 0));
-            return var4 + "\n" + this.wrapFormattedStringToWidth(var7, maxWidth);
-        }
-    }
-
-    private int sizeStringToWidth(String par1Str, int par2) {
-        int var3 = par1Str.length();
-        int var4 = 0;
-        int var5 = 0;
-        int var6 = -1;
-
-        for(boolean var7 = false; var5 < var3; ++var5) {
-            char var8 = par1Str.charAt(var5);
-            switch(var8) {
-                case '\n':
-                    --var5;
-                    break;
-                case ' ':
-                    if (!monospace) {
-                        var6 = var5;
-                    }
-                default:
-                    var4 += this.getCharWidth(var8);
-                    if(var7) {
-                        ++var4;
-                    }
-                    break;
-                case '\u00a7':
-                    if(var5 < var3 - 1) {
-                        ++var5;
-                        char var9 = par1Str.charAt(var5);
-                        if(var9 != 108 && var9 != 76) {
-                            if(var9 == 114 || var9 == 82 || isFormatColor(var9)) {
-                                var7 = false;
-                            }
-                        } else {
-                            var7 = true;
-                        }
-                    }
-            }
-
-            if(var8 == 10) {
-                ++var5;
-                var6 = var5;
-                break;
-            }
-
-            if(var4 > par2) {
-                break;
-            }
-        }
-
-        return var5 != var3 && var6 != -1 && var6 < var5 ? var6 : var5;
-    }
-
-    private static boolean isFormatColor(char par0) {
-        return par0 >= 48 && par0 <= 57 || par0 >= 97 && par0 <= 102 || par0 >= 65 && par0 <= 70;
-    }
-
-    private static boolean isFormatSpecial(char par0) {
-        return par0 >= 107 && par0 <= 111 || par0 >= 75 && par0 <= 79 || par0 == 114 || par0 == 82;
-    }
-
-    private static String getFormatFromString(String par0Str) {
-        StringBuilder var1 = new StringBuilder();
-        int var2 = -1;
-        int var3 = par0Str.length();
-
-        while((var2 = par0Str.indexOf(167, var2 + 1)) != -1) {
-            if(var2 < var3 - 1) {
-                char var4 = par0Str.charAt(var2 + 1);
-                if(isFormatColor(var4)) {
-                    var1 = new StringBuilder("§" + var4);
-                } else if(isFormatSpecial(var4)) {
-                    var1.append("§").append(var4);
-                }
-            }
-        }
-
-        return var1.toString();
-    }
-
-    public boolean getBidiFlag() {
-        return this.bidiFlag;
-    }
-
-    public static String stripColorCodes(String s) {
-        return FORMATTING_CODE_REGEX.matcher(s).replaceAll("");
-    }
-
-    public void drawStringIntoConstrainedBlock(String s, int x, int y, int maxWidth, int argb, boolean isShadow) {
-        this.resetStyles();
-        this.textColor = argb;
-        this.renderSplitString(trimStringNewline(s), x, y, maxWidth, isShadow);
-    }
-
-    public void drawCenteredString(String string, int x, int y, int color) {
-        int length = getStringWidth(string);
-        drawStringWithShadow(string, x - length / 2, y, color);
-    }
-
-    /**
-     * Some characters somehow are recognized as "default" characters while their rendering is not supported.
-     * Have to delete this once workarounds are found.
-     */
-    private static final List<Character> DEFAULT_BLACKLIST = Arrays.asList(
-            '\uff0c', '\u3002', '\u3001', '\u3010', '\u3011', '\uff1b', '\u2019', '\u2018', '\u201c', '\u201d', '\uff1f', '\uff01', '\u00b7'
-    );
-}
diff --git a/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java b/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
index f2b1a9ca6..8f70c5cb5 100644
--- a/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/LoadingScreenRenderer.java
@@ -5,6 +5,7 @@ import static org.lwjgl.opengl.GL11.*;
 import java.util.List;
 import java.util.Random;
 
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.Minecraft;
@@ -207,14 +208,14 @@ public class LoadingScreenRenderer
         }
 
         // Draw title and stage
-        minecraft.font.drawStringWithShadow(title, (width - minecraft.font.getStringWidth(title)) / 2, height / 2 - 4 - 16, 0xffffff);
-        minecraft.font.drawStringWithShadow(stage, (width - minecraft.font.getStringWidth(stage)) / 2, (height / 2 - 4) + 8, 0xffffff);
+        FontHelper.renderCentered(t, this.title, width / 2, height / 2 - 4 - 16).setShadow().call(this.minecraft.font);
+        FontHelper.renderCentered(t, this.stage, width / 2, (height / 2 - 4) + 8).setShadow().call(this.minecraft.font);
 
         // Draw tip
-        minecraft.font.drawStringWithShadow(tip, (width - minecraft.font.getStringWidth(tip)) / 2, (height / 2 - 4) + 32, 0xffffff);
-        
-        minecraft.renderer.endRenderGame(1.0f);
-        
-        minecraft.gameWindow.update();
+        FontHelper.renderCentered(t, this.tip, width / 2, (height / 2 - 4) + 32).setShadow().call(this.minecraft.font);
+
+        this.minecraft.renderer.endRenderGame(1.0f);
+
+        this.minecraft.gameWindow.update();
     }
 }
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 03915e02f..82b871a68 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
@@ -6,7 +6,6 @@ import net.minecraft.client.entity.particle.Particle;
 import net.minecraft.client.entity.particle.ParticleDispatcher;
 import net.minecraft.client.gui.ScreenPhotoMode;
 import net.minecraft.client.gui.modelviewer.ScreenModelViewer;
-import net.minecraft.client.render.block.model.BlockModel;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.block.model.BlockModelLeaves;
 import net.minecraft.client.render.camera.EntityCamera;
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 20ed62e9a..e0071feb7 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
@@ -33,6 +33,8 @@ import net.minecraft.client.render.dynamictexture.DynamicTextureLavaStill;
 import net.minecraft.client.render.dynamictexture.DynamicTextureTrommel;
 import net.minecraft.client.render.dynamictexture.DynamicTextureWaterFlow;
 import net.minecraft.client.render.dynamictexture.DynamicTextureWaterStill;
+import net.minecraft.client.render.font.FontDefault;
+import net.minecraft.client.render.font.FontRendererDefault;
 import net.minecraft.client.render.texture.meta.AnimationProperties;
 import net.minecraft.client.render.texture.stitcher.AtlasStitcher;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
@@ -172,12 +174,17 @@ public class TextureManager {
 
 		Texture texture = textureMap.get(name);
 		if (texture != null) return texture;
+		if (!Minecraft.getMinecraft().texturePackList.anyHasFile(name)) return null;
 
 		try {
-			texture = new TextureFile(name);
-			textureMap.put(name, texture);
-			idToTextureMap.put(texture.id(), texture);
-			return texture;
+			TextureFile t = new TextureFile(name);
+			if (!t.initFileTex(false)) {
+				t.delete();
+				return null;
+			}
+			textureMap.put(name, t);
+			idToTextureMap.put(t.id(), t);
+			return t;
 		} catch (Exception e) {
             LOGGER.error("Failed to create texture for '{}'!", name, e);
 		}
@@ -402,9 +409,9 @@ public class TextureManager {
 		}
 
 		Colors.loadColors();
-		
-		mc.font = new Font(mc, gameSettings, this);
-		
+
+        this.mc.font.init(this.mc.texturePackList);
+
 		mc.skinVariantList.refresh(errors);
 		mc.mainMenuBackground.refresh(errors);
 		
diff --git a/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
index 06044da4e..2d3c03fed 100644
--- a/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
+++ b/game/client/src/main/java/net/minecraft/client/render/TileEntityRenderDispatcher.java
@@ -3,6 +3,7 @@ package net.minecraft.client.render;
 import java.util.*;
 
 import net.minecraft.client.render.camera.ICamera;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.tileentity.*;
 import net.minecraft.core.Global;
@@ -62,7 +63,7 @@ public class TileEntityRenderDispatcher
         return getRenderer(tileEntity) != null;
     }
 
-    public void cacheActiveRenderInfo(World world, TextureManager textureManager, Font font, ICamera camera, float partialTick)
+    public void cacheActiveRenderInfo(World world, TextureManager textureManager, FontRenderer fontRenderer, ICamera camera, float partialTick)
     {
         if(worldObj != world)
         {
@@ -70,7 +71,7 @@ public class TileEntityRenderDispatcher
         }
         this.textureManager = textureManager;
         this.camera = camera;
-        this.font = font;
+        this.fontRenderer = fontRenderer;
         viewLerpYaw = (float) camera.getYRot(partialTick);
         viewLerpPitch = (float) camera.getXRot(partialTick);
         viewLerpPosX = (float) camera.getX(partialTick);
@@ -120,14 +121,14 @@ public class TileEntityRenderDispatcher
         }
     }
 
-    public Font getFont()
+    public FontRenderer getFont()
     {
-        return font;
+        return fontRenderer;
     }
 
     private final Map<Class<?>, TileEntityRenderer<?>> renderers;
     public static TileEntityRenderDispatcher instance = new TileEntityRenderDispatcher();
-    private Font font;
+    private FontRenderer fontRenderer;
     public static double renderPosX;
     public static double renderPosY;
     public static double renderPosZ;
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
index 5a4dd0935..ff4b727cf 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRenderer.java
@@ -1,10 +1,10 @@
 package net.minecraft.client.render.entity;
 
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.core.block.Blocks;
 import org.lwjgl.opengl.GL11;
 
 import net.minecraft.client.render.EntityRenderDispatcher;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.ImageParser;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
@@ -284,7 +284,7 @@ public abstract class EntityRenderer<T extends Entity>
         }
     }
 
-    public Font getFont()
+    public FontRenderer getFont()
     {
         return renderDispatcher.getFont();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
index 771a96bfe..63392a634 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRenderer.java
@@ -2,8 +2,9 @@ package net.minecraft.client.render.entity;
 
 import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.LightmapHelper;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.model.ModelBase;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.Global;
@@ -215,14 +216,14 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
         }
     }
 
-    protected void renderLivingLabel(Tessellator tessellator, T entity, String s, double x, double y, double z, int maxDistance, boolean depthTest)
+    protected void renderLivingLabel(Tessellator t, T entity, String s, double x, double y, double z, int maxDistance, boolean depthTest)
     {
         final float f = (float) renderDispatcher.camera.distanceTo(entity);
         if (f > maxDistance)
         {
             return;
         }
-        final Font font = getFont();
+        final FontRenderer sr = getFont();
         final float f1 = 1.6F;
         final float f2 = 0.01666667F * f1;
         GL11.glPushMatrix();
@@ -238,19 +239,19 @@ public class MobRenderer<T extends Mob> extends EntityRenderer<T>
         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
         byte byte0 = 0;
         GL11.glDisable(3553 /* GL_TEXTURE_2D */);
-        tessellator.startDrawingQuads();
-        final int j = font.getStringWidth(s) / 2;
-        tessellator.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.25F);
-        tessellator.addVertex(-j - 1, -1 + byte0, 0.0D);
-        tessellator.addVertex(-j - 1, 8 + byte0, 0.0D);
-        tessellator.addVertex(j + 1, 8 + byte0, 0.0D);
-        tessellator.addVertex(j + 1, -1 + byte0, 0.0D);
-        tessellator.draw();
+        t.startDrawingQuads();
+        final int j = sr.stringWidth(s) / 2;
+        t.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.25F);
+        t.addVertex(-j - 1, -1 + byte0, 0.0D);
+        t.addVertex(-j - 1, 8 + byte0, 0.0D);
+        t.addVertex(j + 1, 8 + byte0, 0.0D);
+        t.addVertex(j + 1, -1 + byte0, 0.0D);
+        t.draw();
         GL11.glEnable(3553 /* GL_TEXTURE_2D */);
-        font.drawString(s, -font.getStringWidth(s) / 2, byte0, 0x20ffffff);
+        FontHelper.render(t, s, -sr.stringWidth(s) / 2, byte0).setColor(0x20ffffff).call(sr);
         if (!depthTest) GL11.glEnable(2929 /* GL_DEPTH_TEST */);
         GL11.glDepthMask(true);
-        font.drawString(s, -font.getStringWidth(s) / 2, byte0, 0xFFFFFF);
+        FontHelper.render(t, s, -sr.stringWidth(s) / 2, byte0).setColor(0xFFFFFF).call(sr);
         GL11.glEnable(2896 /* GL_LIGHTING */);
         GL11.glDisable(3042 /* GL_BLEND */);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
index 5ef2d7207..4ed76a5e9 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/MobRendererPlayer.java
@@ -2,13 +2,13 @@ package net.minecraft.client.render.entity;
 
 import net.minecraft.client.Minecraft;
 
-import net.minecraft.client.entity.player.PlayerLocal;
 import net.minecraft.client.render.TileEntityRenderDispatcher;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.Lighting;
 import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.PlayerSkinParser;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.tileentity.TileEntityRenderer;
 import net.minecraft.client.render.camera.EntityCamera;
 import net.minecraft.client.render.model.ModelPlayer;
@@ -112,7 +112,7 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
         }
     }
     @Override
-    protected void renderSpecials(Tessellator tessellator, Player entity, double x, double y, double z)
+    protected void renderSpecials(Tessellator t, Player entity, double x, double y, double z)
     {
         if (Minecraft.getMinecraft().thePlayer.getGamemode() != Gamemode.spectator && entity.getGamemode() == Gamemode.spectator) {
             return;
@@ -134,14 +134,14 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
                 {
                     if(entity.isPlayerSleeping())
                     {
-                        renderLivingLabel(tessellator, entity, s, x, y - 1.5D, z, 64, false);
+                        renderLivingLabel(t, entity, s, x, y - 1.5D, z, 64, false);
                     } else
                     {
-                        renderLivingLabel(tessellator, entity, s, x, y, z, 64, false);
+                        renderLivingLabel(t, entity, s, x, y, z, 64, false);
                     }
                 } else
                 {
-                    Font font = getFont();
+                    final FontRenderer font = getFont();
                     GL11.glPushMatrix();
                     GL11.glTranslatef((float) x + 0.0F, (float) y + 2.3F, (float) z);
                     GL11.glNormal3f(0.0F, 1.0F, 0.0F);
@@ -154,17 +154,17 @@ public class MobRendererPlayer extends MobRendererBipedArmored<Player>
                     GL11.glEnable(GL11.GL_BLEND);
                     GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
                     GL11.glDisable(GL11.GL_TEXTURE_2D);
-                    tessellator.startDrawingQuads();
-                    int i = font.getStringWidth(s) / 2;
-                    tessellator.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.25F);
-                    tessellator.addVertex(-i - 1, -1D, 0.0D);
-                    tessellator.addVertex(-i - 1, 8D, 0.0D);
-                    tessellator.addVertex(i + 1, 8D, 0.0D);
-                    tessellator.addVertex(i + 1, -1D, 0.0D);
-                    tessellator.draw();
+                    t.startDrawingQuads();
+                    final int halfWidth = font.stringWidth(s) / 2;
+                    t.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.25F);
+                    t.addVertex(-halfWidth - 1, -1D, 0.0D);
+                    t.addVertex(-halfWidth - 1, 8D, 0.0D);
+                    t.addVertex(halfWidth + 1, 8D, 0.0D);
+                    t.addVertex(halfWidth + 1, -1D, 0.0D);
+                    t.draw();
                     GL11.glEnable(GL11.GL_TEXTURE_2D);
                     GL11.glDepthMask(true);
-                    font.drawString(s, -font.getStringWidth(s) / 2, 0, 0x20ffffff);
+                    FontHelper.renderCentered(t, s, 0, 0).setColor(0x20ffffff).call(font);
                     GL11.glEnable(GL11.GL_LIGHTING);
                     GL11.glDisable(GL11.GL_BLEND);
                     GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/Alignment.java b/game/client/src/main/java/net/minecraft/client/render/font/Alignment.java
new file mode 100644
index 000000000..cfe93d5d1
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/Alignment.java
@@ -0,0 +1,8 @@
+package net.minecraft.client.render.font;
+
+public enum Alignment {
+    LEFT,
+    RIGHT,
+//    JUSTIFIED,
+    CENTERED;
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/Font.java b/game/client/src/main/java/net/minecraft/client/render/font/Font.java
new file mode 100644
index 000000000..bdc0c87fd
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/Font.java
@@ -0,0 +1,26 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texturepack.TexturePackList;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+public interface Font {
+
+    void init(@NotNull TexturePackList packList);
+
+    int textureForChar(char c);
+    char getObfuscatedChar(char c, Random random);
+    boolean canRenderChar(char c);
+
+    double charWidthDouble(char c);
+    default int charWidth(final char c) {
+        return MathHelper.ceil(charWidthDouble(c));
+    }
+
+    int fontHeight();
+
+    double renderChar(Tessellator tessellator, char c, double x, double y, double z, boolean italics);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java b/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java
new file mode 100644
index 000000000..a10d064a5
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java
@@ -0,0 +1,83 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.Texture;
+import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import org.jetbrains.annotations.NotNull;
+
+public class FontDefault extends FontFile {
+    public FontDefault(final @NotNull TextureManager textureManager) {
+        super(textureManager, "/font/font_%02X.png", "/font/glyph_sizes_default.bin");
+    }
+
+    @Override
+    public boolean canRenderChar(final char c) {
+        return c == ' ' || (!DEFAULT_BLACKLIST.contains(c) && ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) >= 0 && textureForChar(c) != 0);
+//        return false;
+    }
+
+    @Override
+    public int textureForChar(final char c) {
+        final int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
+        if (fontIndex < 0) return 0;
+        final int index = fontIndex / GLYPHS_PER_TEXTURE;
+        if (this.texHandleCache[index] != TEXTURE_UNASSIGNED) return this.texHandleCache[index];
+        final Texture texture = this.textureManager.loadTextureNoDefault(String.format(this.textureFormat, index));
+        if (texture == null) {
+            this.texHandleCache[index] = 0;
+            return 0;
+        }
+        this.texHandleCache[index] = texture.id();
+        return texture.id();
+    }
+
+    @Override
+    public double charWidthDouble(final char c) {
+        if (c == ' ') return 4;
+        final int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
+        if (fontIndex < 0) return 0;
+
+        final int upper = this.charWidth[fontIndex] >> 4;
+        final int lower = this.charWidth[fontIndex] & 0x0F;
+        final double fUpper = upper;
+        final double fLower = (lower + 1);
+
+        return (fLower - fUpper) / 2.0D + 1;
+    }
+
+    @Override
+    public double renderChar(final Tessellator tessellator, final char c, final double x, final double y, final double z, final boolean italics) {
+        if (c == ' ') return 4;
+        final int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
+        if (fontIndex < 0) return 0;
+
+        final int shift = italics ? ITALICS_SHIFT : 0;
+
+        final int upper = this.charWidth[fontIndex] >> 4;
+        final int lower = this.charWidth[fontIndex] & 0x0F;
+        final double fUpper = upper;
+        final double fLower = (lower + 1);
+        if (fLower - fUpper == 0) return 0;
+
+        final double epsilon = 0.02/256;
+        final double u = (fontIndex % 16 * 16) + fUpper;
+        final double v = (fontIndex & 255) / 16 * 16;
+        final double uWidth = fLower - fUpper;
+        final double vHeight = 16d;
+
+        final double uMin = u / 256d;
+        final double uMax = (u + uWidth) / 256d;
+        final double vMin = v / 256d;
+        final double vMax = (v + vHeight) / 256d;
+
+        final double width = uWidth/2d;
+        final double height = vHeight/2d;
+
+        tessellator.addVertexWithUV(x + shift,          y,           z, uMin + epsilon, vMin + epsilon);
+        tessellator.addVertexWithUV(x - shift,          y + height,  z, uMin + epsilon, vMax - epsilon);
+        tessellator.addVertexWithUV(x - shift + width,  y + height,  z, uMax - epsilon, vMax - epsilon);
+        tessellator.addVertexWithUV(x + shift + width,  y,           z, uMax - epsilon, vMin + epsilon);
+        return (fLower - fUpper)/2 + 1;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java b/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java
new file mode 100644
index 000000000..a19072aff
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java
@@ -0,0 +1,135 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texture.Texture;
+import net.minecraft.client.render.texturepack.TexturePackList;
+import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+public class FontFile implements Font {
+    /**
+     * Some characters somehow are recognized as "default" characters while their rendering is not supported.
+     * Have to delete this once workarounds are found.
+     */
+    protected static final List<Character> DEFAULT_BLACKLIST = Arrays.asList(
+        '\uff0c', '\u3002', '\u3001', '\u3010', '\u3011', '\uff1b', '\u2019', '\u2018', '\u201c', '\u201d', '\uff1f', '\uff01', '\u00b7'
+    );
+
+    protected static final int ITALICS_SHIFT = 1;
+    protected static final int GLYPHS_PER_TEXTURE = 256;
+    protected static final int TEXTURE_UNASSIGNED = -1;
+
+    protected final byte[] charWidth;
+    protected final int[] texHandleCache;
+
+    protected final @NotNull String textureFormat;
+    protected final @NotNull String glyphSizesPath;
+    protected final @NotNull TextureManager textureManager;
+
+    public FontFile(final @NotNull TextureManager textureManager, @NotNull final String texturesFormat, @NotNull final String glyphSizesPath) {
+        this.textureManager = textureManager;
+        this.textureFormat = texturesFormat;
+        this.glyphSizesPath = glyphSizesPath;
+        this.charWidth = new byte[Character.MAX_VALUE + 1];
+        this.texHandleCache = new int[256];
+    }
+
+    @Override
+    public void init(@NotNull final TexturePackList packList) {
+        Arrays.fill(this.texHandleCache, TEXTURE_UNASSIGNED);
+
+        try (final InputStream glyphStreamDefault = packList.getResourceAsStream(this.glyphSizesPath)) {
+            glyphStreamDefault.read(this.charWidth);
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public int textureForChar(final char c) {
+        final int index = c / GLYPHS_PER_TEXTURE;
+        if (this.texHandleCache[index] != TEXTURE_UNASSIGNED) return this.texHandleCache[index];
+        final Texture texture = this.textureManager.loadTextureNoDefault(String.format(this.textureFormat, index));
+        if (texture == null) {
+            this.texHandleCache[index] = 0;
+            return 0;
+        }
+        this.texHandleCache[index] = texture.id();
+        return texture.id();
+    }
+
+    @Override
+    public char getObfuscatedChar(final char c, final Random random) {
+        if (ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) < 0) return c;
+        char randomChar;
+        int counter = 0;
+        do {
+            randomChar = ChatAllowedCharacters.ALLOWED_CHARACTERS.charAt(random.nextInt(ChatAllowedCharacters.ALLOWED_CHARACTERS.length()));
+            if (counter++ > 1000) {
+                randomChar = c;
+                break;
+            }
+        } while (charWidth(c) != charWidth(randomChar) || !canRenderChar(randomChar));
+        return randomChar;
+    }
+
+    @Override
+    public boolean canRenderChar(final char c) {
+        return c == ' ' || textureForChar(c) != 0;
+    }
+
+    @Override
+    public double charWidthDouble(final char c) {
+        if (c == ' ') return 4;
+        final int upper = this.charWidth[c] >> 4;
+        final int lower = this.charWidth[c] & 0x0F;
+        final double fUpper = upper;
+        final double fLower = (lower + 1);
+
+        return (fLower - fUpper) / 2.0D + 1;
+    }
+
+    @Override
+    public int fontHeight() {
+        return 8;
+    }
+
+    @Override
+    public double renderChar(final Tessellator tessellator, final char c, final double x, final double y, final double z, final boolean italics) {
+        if (c == ' ') return 4;
+        final int shift = italics ? ITALICS_SHIFT : 0;
+
+        final int upper = this.charWidth[c] >> 4;
+        final int lower = this.charWidth[c] & 0x0F;
+        final double fUpper = upper;
+        final double fLower = (lower + 1);
+        if (fLower - fUpper == 0) return 0;
+
+        final double epsilon = 0.02/256;
+        final double u = (c % 16 * 16) + fUpper;
+        final double v = (c & 255) / 16 * 16;
+        final double uWidth = fLower - fUpper;
+        final double vHeight = 16d;
+
+        final double uMin = u / 256d;
+        final double uMax = (u + uWidth) / 256d;
+        final double vMin = v / 256d;
+        final double vMax = (v + vHeight) / 256d;
+
+        final double width = uWidth/2d;
+        final double height = vHeight/2d;
+
+        tessellator.addVertexWithUV(x + shift,          y,           z, uMin + epsilon, vMin + epsilon);
+        tessellator.addVertexWithUV(x - shift,          y + height,  z, uMin + epsilon, vMax - epsilon);
+        tessellator.addVertexWithUV(x - shift + width,  y + height,  z, uMax - epsilon, vMax - epsilon);
+        tessellator.addVertexWithUV(x + shift + width,  y,           z, uMax - epsilon, vMin + epsilon);
+        return (fLower - fUpper)/2 + 1;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java b/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java
new file mode 100644
index 000000000..84e168513
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java
@@ -0,0 +1,66 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texturepack.TexturePackList;
+import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+
+public class FontMonospace extends FontFile{
+    public static final int MONOSPACE_WIDTH = 10;
+
+    public FontMonospace(final @NotNull TextureManager textureManager) {
+        super(textureManager, "/font/mono_%02X.png", "");
+    }
+
+    @Override
+    public void init(@NotNull final TexturePackList packList) {
+        Arrays.fill(this.texHandleCache, TEXTURE_UNASSIGNED);
+        Arrays.fill(this.charWidth, (byte) MONOSPACE_WIDTH);
+    }
+
+    @Override
+    public boolean canRenderChar(final char c) {
+        return !DEFAULT_BLACKLIST.contains(c) && ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) != -1 && (c == ' ' || textureForChar(c) != 0);
+    }
+
+    @Override
+    public double charWidthDouble(final char c) {
+        return MONOSPACE_WIDTH / 2d + 1;
+    }
+
+    @Override
+    public double renderChar(final Tessellator tessellator, final char c, final double x, final double y, final double z, final boolean italics) {
+        if (c != ' ') {
+            final int shift = italics ? ITALICS_SHIFT : 0;
+            final int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
+            if (fontIndex < 0) return 0;
+
+            final double epsilon = 0.02/256;
+            final int upper = this.charWidth[fontIndex] >> 4;
+            final int lower = this.charWidth[fontIndex] & 0x0F;
+            final double fUpper = upper;
+            final double fLower = (lower + 1);
+            final double u = (fontIndex % 16 * 16) + fUpper;
+            final double v = (fontIndex & 255) / 16 * 16;
+            final double uWidth = fLower - fUpper;
+            final double vHeight = 16d;
+
+            final double uMin = u / 256d;
+            final double uMax = (u + uWidth) / 256d;
+            final double vMin = v / 256d;
+            final double vMax = (v + vHeight) / 256d;
+
+            final double width = uWidth/2d;
+            final double height = vHeight/2d;
+
+            tessellator.addVertexWithUV(x + shift,          y,           z, uMin + epsilon, vMin + epsilon);
+            tessellator.addVertexWithUV(x - shift,          y + height,  z, uMin + epsilon, vMax - epsilon);
+            tessellator.addVertexWithUV(x - shift + width,  y + height,  z, uMax - epsilon, vMax - epsilon);
+            tessellator.addVertexWithUV(x + shift + width,  y,           z, uMax - epsilon, vMin + epsilon);
+        }
+        return MONOSPACE_WIDTH / 2d + 1;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontRenderer.java b/game/client/src/main/java/net/minecraft/client/render/font/FontRenderer.java
new file mode 100644
index 000000000..ce7182b92
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontRenderer.java
@@ -0,0 +1,29 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public interface FontRenderer extends Font {
+    void render(@NotNull Tessellator tessellator, @NotNull CharSequence chars, int x, int y, double z, boolean shadow, long baseConfig, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderDouble(@NotNull Tessellator tessellator, @NotNull CharSequence chars, double x, double y, double z, boolean shadow, long baseConfig, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderCentered(@NotNull Tessellator tessellator, @NotNull CharSequence chars, int x, int y, double z, boolean shadow, long baseConfig, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderCenteredDouble(@NotNull Tessellator tessellator, @NotNull CharSequence chars, double x, double y, double z, boolean shadow, long baseConfig, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderWidthConstrained(@NotNull Tessellator tessellator, @NotNull CharSequence chars, int x, int y, double z, boolean shadow, long baseConfig, int maxWidth, @NotNull Alignment alignment, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderWidthConstrainedDouble(@NotNull Tessellator tessellator, @NotNull CharSequence chars, double x, double y, double z, boolean shadow, long baseConfig, double maxWidth, @NotNull Alignment alignment, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderConstrained(@NotNull Tessellator tessellator, @NotNull CharSequence chars, int x, int y, double z, boolean shadow, long baseConfig, int maxWidth, int maxHeight, @NotNull Alignment alignment, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+    void renderConstrainedDouble(@NotNull Tessellator tessellator, @NotNull CharSequence chars, double x, double y, double z, boolean shadow, long baseConfig, double maxWidth, double maxHeight, @NotNull Alignment alignment, double @Nullable [] xPosBuffer, double @Nullable [] yPosBuffer, long @Nullable [] configBuffer);
+
+    @NotNull List<String> splitCharsIntoLines(@NotNull CharSequence chars, double maxWidth, @Nullable List<String> output);
+    @NotNull List<String> splitLinesIntoConstrainedLines(@NotNull List<String> lines, double maxWidth, @Nullable List<String> output);
+    double heightOfConstrainedChars(@NotNull CharSequence chars, double maxWidth);
+    double heightOfLines(@NotNull List<String> lines, double maxWidth);
+
+    double stringWidthDouble(CharSequence chars);
+    default int stringWidth(final CharSequence chars) {
+        return MathHelper.ceil(stringWidthDouble(chars));
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java
new file mode 100644
index 000000000..4f7efce80
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java
@@ -0,0 +1,686 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.client.render.texturepack.TexturePackList;
+import net.minecraft.client.util.helper.Colors;
+import net.minecraft.core.net.command.TextFormatting;
+import net.minecraft.core.util.helper.ChatAllowedCharacters;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class FontRendererDefault implements FontRenderer {
+    public final @NotNull Font fallbackFont;
+    public final @NotNull Font font;
+
+    protected final long @NotNull [] configStack = new long[32];
+    protected byte stackIndex = 0;
+    protected long currentConfig = 0;
+
+    protected int currentTex = -1;
+    protected final Random random;
+
+    protected final List<@NotNull String> localStringList = new ArrayList<>();
+    protected final double[] localXPosBuffer = new double[1];
+    protected final double[] localYPosBuffer = new double[1];
+    protected final long[] localConfigBuffer = new long[1];
+
+    public FontRendererDefault(@NotNull final Font font) {
+        this.fallbackFont = new FontUnicode(Minecraft.getMinecraft().textureManager);
+        this.font = font;
+        this.random = new Random();
+    }
+
+    protected void renderStringInternal(@NotNull final Tessellator tessellator, final @NotNull CharSequence chars, final double x, final double y, final double z, final boolean shadow, final long baseConfig, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        double currX = x;
+        final double currY = y;
+
+        this.random.setSeed(System.currentTimeMillis()/50);
+
+        for (int i = 0; i < chars.length(); i++) {
+            final char c = chars.charAt(i);
+
+            if (c == '§' && i + 1 < chars.length()) {
+                final char cNext = chars.charAt(i + 1);
+                if (cNext == '<') {
+                    int offAmount = 1;
+                    int j = i + 2; // First char after <
+                    final StringBuilder colorValue = new StringBuilder();
+                    boolean ended = false;
+                    while (j < chars.length()) {
+                        offAmount++;
+                        if (chars.charAt(j) == '>'){
+                            ended = true;
+                            break;
+                        }
+                        colorValue.append(chars.charAt(j));
+                        j++;
+                    }
+
+                    if (ended){
+                        long colorInt = 0xFFFFFF;
+                        try { colorInt = decodeHexToLong(colorValue); } catch (final NumberFormatException ignored){}
+
+                        this.currentConfig = SF.setColor(this.currentConfig, (colorInt & 0xFF_00_00_00L) == 0 ? (int) (colorInt & 0x00_FF_FF_FFL) | (SF.getColor(baseConfig) & 0xFF_00_00_00) : ((int)colorInt));
+                        //noinspection AssignmentToForLoopParameter
+                        i += offAmount;
+                        continue;
+                    }
+
+                } else {
+                    final int formatCode = TextFormatting.FORMAT_CHARS.indexOf(cNext);
+                    if (formatCode != -1) {
+                        switch (cNext) {
+                            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': {
+                                this.currentConfig = SF.setColor(this.currentConfig, Colors.allChatColors[MathHelper.clamp(formatCode, 0, 15)].value);
+                                break;
+                            }
+                            case 'k': {
+                                this.currentConfig = SF.setObfuscated(this.currentConfig);
+                                break;
+                            }
+                            case 'l': {
+                                this.currentConfig = SF.setBold(this.currentConfig);
+                                break;
+                            }
+                            case 'm': {
+                                this.currentConfig = SF.setStrikethrough(this.currentConfig);
+                                break;
+                            }
+                            case 'n': {
+                                this.currentConfig = SF.setUnderline(this.currentConfig);
+                                break;
+                            }
+                            case 'o': {
+                                this.currentConfig = SF.setItalic(this.currentConfig);
+                                break;
+                            }
+                            case 'r': {
+                                this.currentConfig = Integer.toUnsignedLong(SF.getColor(baseConfig));
+                                break;
+                            }
+                            case '+': {
+                                if (this.stackIndex == this.configStack.length - 1) {
+                                    break;
+                                }
+                                this.configStack[this.stackIndex] = this.currentConfig;
+                                this.stackIndex++;
+                                break;
+                            }
+                            case '-': {
+                                if (this.stackIndex == 0) {
+                                    break;
+                                }
+                                this.stackIndex--;
+                                this.currentConfig = this.configStack[this.stackIndex];
+                                break;
+                            }
+                        }
+                        //noinspection AssignmentToForLoopParameter
+                        i++;
+                        continue;
+                    }
+                }
+            }
+
+            final int tex = textureForChar(c);
+            if (this.currentTex != tex) {
+                this.currentTex = tex;
+                GL11.glBindTexture(GL11.GL_TEXTURE_2D, tex);
+            }
+
+            currX += renderCharInternal(tessellator, c, currX, currY, z, SF.getColor(this.currentConfig), shadow);
+        }
+
+        if (xPosBuffer != null) {
+            xPosBuffer[0] = currX;
+        }
+        if (yPosBuffer != null) {
+            yPosBuffer[0] = currY + fontHeight() + 1;
+        }
+        if (configBuffer != null) {
+            configBuffer[0] = this.currentConfig;
+        }
+    }
+
+    protected double renderCharInternal(@NotNull final Tessellator tessellator, final char c, final double x, final double y, final double z, final int color, final boolean shadow) {
+        final int rgb = color & 0xFFFFFF;
+        final int shadowRGB = (color & 0xFCFCFC) >> 2; // Divide RGB by 4
+        final int a = (color & 0xFF_00_00_00) != 0 ? (color >> 24) & 0xFF : 0xFF;
+        tessellator.startDrawingQuads();
+        double shift;
+        final int fontIndex = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c);
+        if (SF.isObfuscated(this.currentConfig) && c != ' ' && fontIndex > 0) {
+            shift = charWidth(c);
+            final char randomChar = getObfuscatedChar(c, this.random);
+
+            if (shadow) {
+                tessellator.setColorRGBA_I(shadowRGB, a);
+                renderChar(tessellator, randomChar, x + 1, y + 1, z, SF.isItalic(this.currentConfig));
+                if (SF.isBold(this.currentConfig)) renderChar(tessellator, randomChar, x + 2, y + 1, z, SF.isItalic(this.currentConfig));
+            }
+
+            tessellator.setColorRGBA_I(rgb, a);
+            renderChar(tessellator, randomChar, x, y, z, SF.isItalic(this.currentConfig));
+            if (SF.isBold(this.currentConfig)) {
+                renderChar(tessellator, randomChar, x + 1, y, z, SF.isItalic(this.currentConfig));
+                shift++;
+            }
+
+        } else {
+            if (shadow) {
+                tessellator.setColorRGBA_I(shadowRGB, a);
+                renderChar(tessellator, c, x + 1, y + 1, z, SF.isItalic(this.currentConfig));
+                if (SF.isBold(this.currentConfig)) renderChar(tessellator, c, x + 2, y + 1, z, SF.isItalic(this.currentConfig));
+            }
+
+            tessellator.setColorRGBA_I(rgb, a);
+            shift = renderChar(tessellator, c, x, y, z, SF.isItalic(this.currentConfig));
+            if (SF.isBold(this.currentConfig)) {
+                renderChar(tessellator, c, x + 1, y, z, SF.isItalic(this.currentConfig));
+                shift++;
+            }
+        }
+        tessellator.draw();
+
+        if (SF.isStrikethrough(this.currentConfig)) {
+            GL11.glDisable(GL11.GL_TEXTURE_2D);
+            tessellator.startDrawingQuads();
+            if (shadow) {
+                tessellator.setColorRGBA_I(shadowRGB, a);
+                tessellator.addVertex(x + 1,        y + 1 + fontHeight() / 2d,       0.0D);
+                tessellator.addVertex(x + 1 + shift,y + 1 + fontHeight() / 2d,       0.0D);
+                tessellator.addVertex(x + 1 + shift,y + 1 + fontHeight() / 2d - 1.0F,0.0D);
+                tessellator.addVertex(x + 1,        y + 1 + fontHeight() / 2d - 1.0F,0.0D);
+            }
+            tessellator.setColorRGBA_I(rgb, a);
+            tessellator.addVertex(x,        y + fontHeight() / 2d,       0.0D);
+            tessellator.addVertex(x + shift,y + fontHeight() / 2d,       0.0D);
+            tessellator.addVertex(x + shift,y + fontHeight() / 2d - 1.0F,0.0D);
+            tessellator.addVertex(x,        y + fontHeight() / 2d - 1.0F,0.0D);
+            tessellator.draw();
+            GL11.glEnable(GL11.GL_TEXTURE_2D);
+        }
+
+        if (SF.isUnderline(this.currentConfig)) {
+            GL11.glDisable(GL11.GL_TEXTURE_2D);
+            tessellator.startDrawingQuads();
+            if (shadow) {
+                tessellator.setColorRGBA_I(shadowRGB, a);
+                tessellator.addVertex(x,            y + 2 + fontHeight(),        0.0D);
+                tessellator.addVertex(x + 1 + shift,y + 2 + fontHeight(),        0.0D);
+                tessellator.addVertex(x + 1 + shift,y + 2 + fontHeight() - 1.0F, 0.0D);
+                tessellator.addVertex(x,            y + 2 + fontHeight() - 1.0F, 0.0D);
+            }
+            tessellator.setColorRGBA_I(rgb, a);
+            tessellator.addVertex(x - 1,    y + 1 + fontHeight(),        0.0D);
+            tessellator.addVertex(x + shift,y + 1 + fontHeight(),        0.0D);
+            tessellator.addVertex(x + shift,y + 1 + fontHeight() - 1.0F, 0.0D);
+            tessellator.addVertex(x - 1,    y + 1 + fontHeight() - 1.0F, 0.0D);
+            tessellator.draw();
+            GL11.glEnable(GL11.GL_TEXTURE_2D);
+        }
+        return shift;
+    }
+    @Override
+    public void renderDouble(@NotNull final Tessellator tessellator, final @NotNull CharSequence chars, final double x, final double y, final double z, final boolean shadow, final long baseConfig, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.currentTex = -1;
+        this.currentConfig = baseConfig;
+        this.stackIndex = 0;
+        renderStringInternal(tessellator, chars, x, y, z, shadow, baseConfig, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    @Override
+    public void render(@NotNull final Tessellator tessellator, final @NotNull CharSequence chars, final int x, final int y, final double z, final boolean shadow, final long baseConfig, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        renderDouble(tessellator, chars, x, y, z, shadow, baseConfig, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    @Override
+    public void renderCenteredDouble(@NotNull final Tessellator tessellator, final @NotNull CharSequence chars, final double x, final double y, final double z, final boolean shadow, final long baseConfig, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        renderDouble(tessellator, chars, x - stringWidthDouble(chars)/2d, y, z, shadow, baseConfig, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    @Override
+    public void renderCentered(@NotNull final Tessellator tessellator, final @NotNull CharSequence chars, final int x, final int y, final double z, final boolean shadow, final long baseConfig, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        render(tessellator, chars, x - stringWidth(chars)/2, y, z, shadow, baseConfig, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    @Override
+    public void renderWidthConstrainedDouble(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y, final double z, final boolean shadow, final long baseConfig, final double maxWidth, @NotNull final Alignment alignment, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.currentTex = -1;
+        this.currentConfig = baseConfig;
+        this.stackIndex = 0;
+
+        final List<String> lines = splitCharsIntoLines(chars, maxWidth, this.localStringList);
+
+        double currY = y;
+        switch (alignment) {
+            case LEFT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x, currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+            case RIGHT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x + (maxWidth - stringWidthDouble(line)), currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+            case CENTERED: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x + (maxWidth - stringWidthDouble(line))/2, currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+        }
+
+        if (xPosBuffer != null) {
+            xPosBuffer[0] = x + maxWidth;
+        }
+        if (yPosBuffer != null) {
+            yPosBuffer[0] = currY;
+        }
+        if (configBuffer != null) {
+            configBuffer[0] = this.localConfigBuffer[0];
+        }
+    }
+
+    @Override
+    public void renderWidthConstrained(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y, final double z, final boolean shadow, final long baseConfig, final int maxWidth, @NotNull final Alignment alignment, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.currentTex = -1;
+        this.currentConfig = baseConfig;
+        this.stackIndex = 0;
+
+        final List<String> lines = splitCharsIntoLines(chars, maxWidth, this.localStringList);
+
+        int currY = y;
+        switch (alignment) {
+            case LEFT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x, currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+            case RIGHT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x + (maxWidth - stringWidth(line)), currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+            case CENTERED: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, (int)(x + (maxWidth - stringWidth(line))/2), currY, z, shadow, baseConfig, this.localXPosBuffer, this.localYPosBuffer, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                }
+                break;
+            }
+        }
+
+        if (xPosBuffer != null) {
+            xPosBuffer[0] = x + maxWidth;
+        }
+        if (yPosBuffer != null) {
+            yPosBuffer[0] = currY;
+        }
+        if (configBuffer != null) {
+            configBuffer[0] = this.localConfigBuffer[0];
+        }
+    }
+
+    @Override
+    public void renderConstrainedDouble(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y, final double z, final boolean shadow, final long baseConfig, final double maxWidth, final double maxHeight, @NotNull final Alignment alignment, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.currentTex = -1;
+        this.currentConfig = baseConfig;
+        this.stackIndex = 0;
+
+        final List<String> lines = splitCharsIntoLines(chars, maxWidth, this.localStringList);
+
+        double currY = y;
+        this.localConfigBuffer[0] = baseConfig;
+        switch (alignment) {
+            case LEFT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x, currY, z, shadow, baseConfig, null, null, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                    if ((currY - y) > maxHeight) break;
+                }
+                break;
+            }
+            case RIGHT: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderStringInternal(tessellator, line, x + (maxWidth - stringWidthDouble(line)), currY, z, shadow, baseConfig, null, null, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                    if ((currY - y) > maxHeight) break;
+                }
+                break;
+            }
+            case CENTERED: {
+                for (int i = 0; i < lines.size(); i++) {
+                    final String line = lines.get(i);
+                    renderCenteredDouble(tessellator, line, x + maxWidth/2, currY, z, shadow, baseConfig, null, null, this.localConfigBuffer);
+                    currY += fontHeight() + 1;
+                    if ((currY - y) > maxHeight) break;
+                }
+                break;
+            }
+        }
+
+        if (xPosBuffer != null) {
+            xPosBuffer[0] = x + maxWidth;
+        }
+        if (yPosBuffer != null) {
+            yPosBuffer[0] = currY;
+        }
+        if (configBuffer != null) {
+            configBuffer[0] = this.localConfigBuffer[0];
+        }
+    }
+
+    @Override
+    public void renderConstrained(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y, final double z, final boolean shadow, final long baseConfig, final int maxWidth, final int maxHeight, @NotNull final Alignment alignment, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        renderConstrainedDouble(tessellator, chars, x, y, z, shadow, baseConfig, maxWidth, maxHeight, alignment, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    private static final StringBuilder splitLineIntoConstrainedLine_lineBuilder = new StringBuilder();
+    private static final StringBuilder splitLineIntoConstrainedLine_wordBuilder = new StringBuilder();
+    protected void splitLineIntoConstrainedLine(final @NotNull CharSequence line, final double maxWidth, final @NotNull List<String> output) {
+        final double dashWidth = charWidthDouble('-');
+        final double spaceWidth = charWidthDouble(' ');
+
+        double currLineWidth = 0;
+        double currWordWidth = 0;
+
+        splitLineIntoConstrainedLine_lineBuilder.setLength(0);
+        splitLineIntoConstrainedLine_wordBuilder.setLength(0);
+
+        final int length = line.length();
+        for (int i = 0; i < length; i++) {
+            final char c = line.charAt(i);
+
+            if (c == '\n') {
+                splitLineIntoConstrainedLine_lineBuilder.append(splitLineIntoConstrainedLine_wordBuilder);
+                splitLineIntoConstrainedLine_wordBuilder.setLength(0);
+                currWordWidth = 0;
+
+                output.add(splitLineIntoConstrainedLine_lineBuilder.toString());
+                splitLineIntoConstrainedLine_lineBuilder.setLength(0);
+                currLineWidth = 0;
+                continue;
+            }
+
+            if (c == '\t') {
+                splitLineIntoConstrainedLine_wordBuilder.append("   ");
+                currWordWidth += spaceWidth * 3;
+                continue;
+            }
+
+            if (c == '§' && i + 1 < length) { // Skip formatting
+                final char cN = line.charAt(i + 1);
+                if (cN == '<') {
+                    int offAmount = 1;
+                    int j = i + 2; // first char after '<'
+                    boolean ended = false;
+                    while (j < length) {
+                        offAmount++;
+                        if (line.charAt(j) == '>'){
+                            ended = true;
+                            break;
+                        }
+                        j++;
+                    }
+
+                    if (ended){
+                        // Add all entire rgb format symbols to word and skip index to next char after
+                        splitLineIntoConstrainedLine_wordBuilder.append(line, i, i + offAmount + 1);
+                        //noinspection AssignmentToForLoopParameter
+                        i += offAmount;
+                        continue;
+                    }
+                } else if (TextFormatting.FORMAT_CHARS.indexOf(cN) != -1) {
+                    // Add format symbols then skip to index after
+                    splitLineIntoConstrainedLine_wordBuilder.append(line, i, i + 2);
+                    //noinspection AssignmentToForLoopParameter
+                    i++;
+                    continue;
+                }
+            }
+
+            final double charWidth = charWidthDouble(c);
+            if (currWordWidth + charWidth + dashWidth > maxWidth) {
+                splitLineIntoConstrainedLine_wordBuilder.append('-');
+                splitLineIntoConstrainedLine_lineBuilder.append(splitLineIntoConstrainedLine_wordBuilder);
+
+                splitLineIntoConstrainedLine_wordBuilder.setLength(0);
+                splitLineIntoConstrainedLine_wordBuilder.append(c);
+                currWordWidth = charWidth;
+
+                output.add(splitLineIntoConstrainedLine_lineBuilder.toString().trim());
+                splitLineIntoConstrainedLine_lineBuilder.setLength(0);
+                currLineWidth = 0;
+                continue;
+            }
+
+            if (currLineWidth + currWordWidth + charWidth > maxWidth) { //
+                if (c == ' ') {
+                    splitLineIntoConstrainedLine_lineBuilder.append(splitLineIntoConstrainedLine_wordBuilder);
+                } else {
+                    splitLineIntoConstrainedLine_wordBuilder.append(c);
+                    currWordWidth += charWidth;
+                }
+                output.add(splitLineIntoConstrainedLine_lineBuilder.toString().trim());
+                splitLineIntoConstrainedLine_lineBuilder.setLength(0);
+                currLineWidth = 0;
+                continue;
+            }
+
+            if (c == ' ') {
+                splitLineIntoConstrainedLine_lineBuilder.append(splitLineIntoConstrainedLine_wordBuilder).append(' ');
+                currLineWidth += currWordWidth + spaceWidth;
+
+                splitLineIntoConstrainedLine_wordBuilder.setLength(0);
+                currWordWidth = 0;
+                continue;
+            }
+
+            splitLineIntoConstrainedLine_wordBuilder.append(c);
+            currWordWidth += charWidth;
+        }
+        splitLineIntoConstrainedLine_lineBuilder.append(splitLineIntoConstrainedLine_wordBuilder);
+        final String remainder = splitLineIntoConstrainedLine_lineBuilder.toString().trim();
+        if (!remainder.isEmpty()) {
+            output.add(remainder);
+        }
+    }
+    @Override
+    public @NotNull List<String> splitCharsIntoLines(@NotNull final CharSequence chars, final double maxWidth, @Nullable final List<String> output) {
+        final @NotNull List<String> o = output == null ? new ArrayList<>() : output;
+        o.clear();
+        splitLineIntoConstrainedLine(chars, maxWidth, o);
+        return o;
+    }
+
+    @Override
+    public @NotNull List<String> splitLinesIntoConstrainedLines(@NotNull final List<String> lines, final double maxWidth, @Nullable final List<String> output) {
+        final @NotNull List<String> o = output == null ? new ArrayList<>() : output;
+        o.clear();
+        for (int i = 0; i < lines.size(); i++) {
+            splitLineIntoConstrainedLine(lines.get(i), maxWidth, o);
+        }
+        return o;
+    }
+
+    @Override
+    public double heightOfConstrainedChars(@NotNull final CharSequence chars, final double maxWidth) {
+        splitCharsIntoLines(chars, maxWidth, this.localStringList);
+        return this.localStringList.size() * (fontHeight() + 1);
+    }
+
+    @Override
+    public double heightOfLines(@NotNull final List<@NotNull String> lines, final double maxWidth) {
+        splitLinesIntoConstrainedLines(lines, maxWidth, this.localStringList);
+        return this.localStringList.size() * (fontHeight() + 1);
+    }
+
+    @Override
+    public void init(@NotNull final TexturePackList packList) {
+        this.font.init(packList);
+        this.fallbackFont.init(packList);
+    }
+
+    @Override
+    public int textureForChar(final char c) {
+        return getFont(c).textureForChar(c);
+    }
+
+    @Override
+    public char getObfuscatedChar(final char c, final Random random) {
+        return getFont(c).getObfuscatedChar(c, random);
+    }
+
+    @Override
+    public boolean canRenderChar(final char c) {
+        return this.font.canRenderChar(c) || this.fallbackFont.canRenderChar(c);
+    }
+
+    @Override
+    public double charWidthDouble(final char c) {
+        return getFont(c).charWidthDouble(c);
+    }
+
+    @Override
+    public double stringWidthDouble(final CharSequence chars) {
+        double width = 0;
+        final int length = chars.length();
+        for (int i = 0; i < length; i++) {
+            final char c = chars.charAt(i);
+
+            if (c == '§' && i + 1 < length) { // Skip formatting
+                final char cN = chars.charAt(i + 1);
+                if (cN == '<') {
+                    int offAmount = 1;
+                    int j = i + 2; // first char after '<'
+                    boolean ended = false;
+                    while (j < length) {
+                        offAmount++;
+                        if (chars.charAt(j) == '>'){
+                            ended = true;
+                            break;
+                        }
+                        j++;
+                    }
+
+                    if (ended){
+                        //noinspection AssignmentToForLoopParameter
+                        i += offAmount;
+                        continue;
+                    }
+                } else if (TextFormatting.FORMAT_CHARS.indexOf(cN) != -1) {
+                    //noinspection AssignmentToForLoopParameter
+                    i++;
+                    continue;
+                }
+            }
+
+            width += charWidthDouble(c);
+        }
+        return width;
+    }
+
+    @Override
+    public int fontHeight() {
+        return getFont().fontHeight();
+    }
+
+    @Override
+    public double renderChar(final Tessellator tessellator, final char c, final double x, final double y, final double z, final boolean italics) {
+        return getFont(c).renderChar(tessellator, c, x, y, z, italics);
+    }
+
+    protected @NotNull Font getFont(final char c) {
+        if (Minecraft.getMinecraft().gameSettings.forceUnicodeFont.value || !this.font.canRenderChar(c)) return this.fallbackFont;
+        return this.font;
+    }
+
+    protected @NotNull Font getFont() {
+        if (Minecraft.getMinecraft().gameSettings.forceUnicodeFont.value) return this.fallbackFont;
+        return this.font;
+    }
+
+    public static int decodeHexToInt(final @NotNull CharSequence hexSequence) throws NumberFormatException {
+        int value = 0;
+        final int length = hexSequence.length();
+        for (int i = 0; i < length; i++) {
+            final char c = hexSequence.charAt(length - i - 1);
+            switch (c) {
+                case '0': { break; }
+                case '1': { value |= 0x1 << (4 * i); break; }
+                case '2': { value |= 0x2 << (4 * i); break; }
+                case '3': { value |= 0x3 << (4 * i); break; }
+                case '4': { value |= 0x4 << (4 * i); break; }
+                case '5': { value |= 0x5 << (4 * i); break; }
+                case '6': { value |= 0x6 << (4 * i); break; }
+                case '7': { value |= 0x7 << (4 * i); break; }
+                case '8': { value |= 0x8 << (4 * i); break; }
+                case '9': { value |= 0x9 << (4 * i); break; }
+                case 'A': case 'a': { value |= 0xA << (4 * i); break; }
+                case 'B': case 'b': { value |= 0xB << (4 * i); break; }
+                case 'C': case 'c': { value |= 0xC << (4 * i); break; }
+                case 'D': case 'd': { value |= 0xD << (4 * i); break; }
+                case 'E': case 'e': { value |= 0xE << (4 * i); break; }
+                case 'F': case 'f': { value |= 0xF << (4 * i); break; }
+                default:
+                    throw new NumberFormatException("Illegal non hex char '" + c + "'");
+            }
+        }
+        return value;
+    }
+
+    public static long decodeHexToLong(final @NotNull CharSequence hexSequence) throws NumberFormatException {
+        long value = 0;
+        final int length = hexSequence.length();
+        for (int i = 0; i < length; i++) {
+            final char c = hexSequence.charAt(length - i - 1);
+            switch (c) {
+                case '0': { break; }
+                case '1': { value |= 0x1L << (4 * i); break; }
+                case '2': { value |= 0x2L << (4 * i); break; }
+                case '3': { value |= 0x3L << (4 * i); break; }
+                case '4': { value |= 0x4L << (4 * i); break; }
+                case '5': { value |= 0x5L << (4 * i); break; }
+                case '6': { value |= 0x6L << (4 * i); break; }
+                case '7': { value |= 0x7L << (4 * i); break; }
+                case '8': { value |= 0x8L << (4 * i); break; }
+                case '9': { value |= 0x9L << (4 * i); break; }
+                case 'A': case 'a': { value |= 0xAL << (4 * i); break; }
+                case 'B': case 'b': { value |= 0xBL << (4 * i); break; }
+                case 'C': case 'c': { value |= 0xCL << (4 * i); break; }
+                case 'D': case 'd': { value |= 0xDL << (4 * i); break; }
+                case 'E': case 'e': { value |= 0xEL << (4 * i); break; }
+                case 'F': case 'f': { value |= 0xFL << (4 * i); break; }
+                default:
+                    throw new NumberFormatException("Illegal non hex char '" + c + "'");
+            }
+        }
+        return value;
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontUnicode.java b/game/client/src/main/java/net/minecraft/client/render/font/FontUnicode.java
new file mode 100644
index 000000000..911b9c463
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/FontUnicode.java
@@ -0,0 +1,15 @@
+package net.minecraft.client.render.font;
+
+import net.minecraft.client.render.TextureManager;
+import org.jetbrains.annotations.NotNull;
+
+public class FontUnicode extends FontFile {
+    public FontUnicode(final @NotNull TextureManager textureManager) {
+        super(textureManager, "/font/glyph_%02X.png", "/font/glyph_sizes.bin");
+    }
+    @Override
+    public boolean canRenderChar(final char c) {
+        return c == ' ' || textureForChar(c) != 0;
+    }
+
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/SF.java b/game/client/src/main/java/net/minecraft/client/render/font/SF.java
new file mode 100644
index 000000000..b2751647c
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/SF.java
@@ -0,0 +1,63 @@
+package net.minecraft.client.render.font;
+
+/**
+ * Short for String Formatting
+ */
+public final class SF {
+    public static final long MASK_COLOR = 0x00_00_00_00__FF_FF_FF_FFL;
+    public static final long ITALIC = (0b0000_0001L << 32);
+    public static final long UNDERLINE = (0b0000_0010L << 32);
+    public static final long STRIKETHROUGH = (0b0000_0100L << 32);
+    public static final long BOLD = (0b0000_1000L << 32);
+    public static final long OBFUSCATED = (0b0001_0000L << 32);
+
+    private SF() {}
+
+    public static long setItalic(final long config) {
+        return config | ITALIC;
+    }
+
+    public static boolean isItalic(final long config) {
+        return (config & ITALIC) != 0;
+    }
+
+    public static long setUnderline(final long config) {
+        return config | UNDERLINE;
+    }
+
+    public static boolean isUnderline(final long config) {
+        return (config & UNDERLINE) != 0;
+    }
+
+    public static long setStrikethrough(final long config) {
+        return config | STRIKETHROUGH;
+    }
+
+    public static boolean isStrikethrough(final long config) {
+        return (config & STRIKETHROUGH) != 0;
+    }
+
+    public static long setBold(final long config) {
+        return config | BOLD;
+    }
+
+    public static boolean isBold(final long config) {
+        return (config & BOLD) != 0;
+    }
+
+    public static long setObfuscated(final long config) {
+        return config | OBFUSCATED;
+    }
+
+    public static boolean isObfuscated(final long config) {
+        return (config & OBFUSCATED) != 0;
+    }
+
+    public static long setColor(final long config, final int color) {
+        return (config & ~MASK_COLOR) | color & MASK_COLOR;
+    }
+
+    public static int getColor(final long config) {
+        return (int) (config & MASK_COLOR);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/FontHelper.java b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/FontHelper.java
new file mode 100644
index 000000000..0c01a0737
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/FontHelper.java
@@ -0,0 +1,75 @@
+package net.minecraft.client.render.font.renderhelper;
+
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.MathHelper;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("unused")
+public final class FontHelper {
+    public static final long CONFIG_DEFAULT = 0xFF_FF_FF_FFL;
+    private static final double @NotNull [] xPosBuffer = new double[1];
+    private static final double @NotNull [] yPosBuffer = new double[1];
+    private static final long @NotNull [] configBuffer = new long[1];
+
+    private static final RenderIntegerBase method_render = new RenderIntegerBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.render(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderDoubleBase method_renderDouble = new RenderDoubleBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderDouble(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderIntegerBase method_renderCentered = new RenderIntegerBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderCentered(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderDoubleBase method_renderCenteredDouble = new RenderDoubleBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderCenteredDouble(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderIntegerConstrainedBase method_renderWidthConstrained = new RenderIntegerConstrainedBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderWidthConstrained(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.maxWidth, this.alignment, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderDoubleConstrainedBase method_renderWidthConstrainedDouble = new RenderDoubleConstrainedBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderWidthConstrainedDouble(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.maxWidth, this.alignment, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderIntegerConstrainedBase method_renderConstrained = new RenderIntegerConstrainedBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderConstrained(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.maxWidth, this.maxHeight, this.alignment, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private static final RenderDoubleConstrainedBase method_renderConstrainedDouble = new RenderDoubleConstrainedBase() { @Override public void call(@NotNull final FontRenderer fontRenderer) {
+        fontRenderer.renderConstrainedDouble(this.tessellator, this.chars, this.x, this.y, this.z, this.shadow, this.config, this.maxWidth, this.maxHeight, this.alignment, this.xPosBuffer, this.yPosBuffer, this.configBuffer);}};
+
+    private FontHelper() {}
+
+    public static @NotNull RenderIntegerBase render(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y) {
+        return method_render.init(tessellator, chars, x, y, xPosBuffer, yPosBuffer, configBuffer);
+    }
+    public static @NotNull RenderDoubleBase renderDouble(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y) {
+        return method_renderDouble.init(tessellator, chars, x, y, xPosBuffer, yPosBuffer, configBuffer);
+    }
+    public static @NotNull RenderIntegerBase renderCentered(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y) {
+        return method_renderCentered.init(tessellator, chars, x, y, xPosBuffer, yPosBuffer, configBuffer);
+    }
+    public static @NotNull RenderDoubleBase renderDoubleCentered(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y) {
+        return method_renderCenteredDouble.init(tessellator, chars, x, y, xPosBuffer, yPosBuffer, configBuffer);
+    }
+    public static @NotNull RenderIntegerConstrainedBase renderWidthConstrained(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y, final int maxWidth) {
+        return method_renderWidthConstrained.init(tessellator, chars, x, y, maxWidth, Integer.MAX_VALUE, xPosBuffer, yPosBuffer, configBuffer);
+    }
+    public static @NotNull RenderDoubleConstrainedBase renderWidthConstrainedDouble(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y, final double maxWidth) {
+        return method_renderWidthConstrainedDouble.init(tessellator, chars, x, y, maxWidth, Double.MAX_VALUE, xPosBuffer, yPosBuffer, configBuffer);
+    }
+
+    public static int getLastEndingX() {
+        return MathHelper.ceil(xPosBuffer[0]);
+    }
+    public static double getLastEndingXDouble() {
+        return xPosBuffer[0];
+    }
+    public static int getLastEndingY() {
+        return MathHelper.ceil(yPosBuffer[0]);
+    }
+    public static double getLastEndingYDouble() {
+        return yPosBuffer[0];
+    }
+    public static long getLastConfig() {
+        return configBuffer[0];
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleBase.java b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleBase.java
new file mode 100644
index 000000000..bbf262aea
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleBase.java
@@ -0,0 +1,98 @@
+package net.minecraft.client.render.font.renderhelper;
+
+import net.minecraft.client.render.font.SF;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.Color;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("unused")
+public abstract class RenderDoubleBase {
+    protected @NotNull Tessellator tessellator;
+    protected @NotNull CharSequence chars;
+    protected double x;
+    protected double y;
+    protected double z;
+    protected double @Nullable [] xPosBuffer;
+    protected double @Nullable [] yPosBuffer;
+    protected long @Nullable [] configBuffer;
+    protected long config;
+    protected boolean shadow;
+    RenderDoubleBase() {
+
+    }
+
+    public @NotNull RenderDoubleBase init(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.tessellator = tessellator;
+        this.chars = chars;
+        this.x = x;
+        this.y = y;
+        this.z = 0;
+        this.xPosBuffer = xPosBuffer;
+        this.yPosBuffer = yPosBuffer;
+        this.configBuffer = configBuffer;
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setConfig(final long config) {
+        this.config = config;
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase resetConfig() {
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        this.z = 0;
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setZ(final double zLevel) {
+        this.z = zLevel;
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setColor(final @NotNull Color color) {
+        this.config = SF.setColor(this.config, color.value);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setColor(final int argb) {
+        this.config = SF.setColor(this.config, argb);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setItalic() {
+        this.config = SF.setItalic(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setUnderline() {
+        this.config = SF.setUnderline(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setStrikethrough() {
+        this.config = SF.setStrikethrough(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setBold() {
+        this.config = SF.setBold(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setObfuscated() {
+        this.config = SF.setObfuscated(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleBase setShadow() {
+        this.shadow = true;
+        return this;
+    }
+
+    public abstract void call(@NotNull FontRenderer fontRenderer);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleConstrainedBase.java b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleConstrainedBase.java
new file mode 100644
index 000000000..56904dfb6
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderDoubleConstrainedBase.java
@@ -0,0 +1,110 @@
+package net.minecraft.client.render.font.renderhelper;
+
+import net.minecraft.client.render.font.Alignment;
+import net.minecraft.client.render.font.SF;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.Color;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("unused")
+public abstract class RenderDoubleConstrainedBase {
+    protected @NotNull Tessellator tessellator;
+    protected @NotNull CharSequence chars;
+    protected double x;
+    protected double y;
+    protected double z;
+    protected double maxWidth;
+    protected double maxHeight;
+    protected double @Nullable [] xPosBuffer;
+    protected double @Nullable [] yPosBuffer;
+    protected long @Nullable [] configBuffer;
+    protected @NotNull Alignment alignment;
+    protected long config;
+    protected boolean shadow;
+    RenderDoubleConstrainedBase() {
+
+    }
+
+    public @NotNull RenderDoubleConstrainedBase init(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final double x, final double y, final double maxWidth, final double maxHeight, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.tessellator = tessellator;
+        this.chars = chars;
+        this.x = x;
+        this.y = y;
+        this.z = 0;
+        this.maxWidth = maxWidth;
+        this.maxHeight = maxHeight;
+        this.xPosBuffer = xPosBuffer;
+        this.yPosBuffer = yPosBuffer;
+        this.configBuffer = configBuffer;
+        this.alignment = Alignment.LEFT;
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setConfig(final long config) {
+        this.config = config;
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase resetConfig() {
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        this.z = 0;
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setZ(final double zLevel) {
+        this.z = zLevel;
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setColor(final @NotNull Color color) {
+        this.config = SF.setColor(this.config, color.value);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setColor(final int argb) {
+        this.config = SF.setColor(this.config, argb);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setItalic() {
+        this.config = SF.setItalic(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setUnderline() {
+        this.config = SF.setUnderline(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setStrikethrough() {
+        this.config = SF.setStrikethrough(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setBold() {
+        this.config = SF.setBold(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setObfuscated() {
+        this.config = SF.setObfuscated(this.config);
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setShadow() {
+        this.shadow = true;
+        return this;
+    }
+
+    public @NotNull RenderDoubleConstrainedBase setAlignment(@NotNull final Alignment alignment) {
+        this.alignment = alignment;
+        return this;
+    }
+
+    public abstract void call(@NotNull FontRenderer fontRenderer);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerBase.java b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerBase.java
new file mode 100644
index 000000000..c92e2ad89
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerBase.java
@@ -0,0 +1,98 @@
+package net.minecraft.client.render.font.renderhelper;
+
+import net.minecraft.client.render.font.SF;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.Color;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("unused")
+public abstract class RenderIntegerBase {
+    protected @NotNull Tessellator tessellator;
+    protected @NotNull CharSequence chars;
+    protected int x;
+    protected int y;
+    protected double z;
+    protected double @Nullable [] xPosBuffer;
+    protected double @Nullable [] yPosBuffer;
+    protected long @Nullable [] configBuffer;
+    protected long config;
+    protected boolean shadow;
+    RenderIntegerBase() {
+
+    }
+
+    public @NotNull RenderIntegerBase init(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.tessellator = tessellator;
+        this.chars = chars;
+        this.x = x;
+        this.y = y;
+        this.z = 0;
+        this.xPosBuffer = xPosBuffer;
+        this.yPosBuffer = yPosBuffer;
+        this.configBuffer = configBuffer;
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setConfig(final long config) {
+        this.config = config;
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase resetConfig() {
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        this.z = 0;
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setZ(final double zLevel) {
+        this.z = zLevel;
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setColor(final @NotNull Color color) {
+        this.config = SF.setColor(this.config, color.value);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setColor(final int argb) {
+        this.config = SF.setColor(this.config, argb);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setItalic() {
+        this.config = SF.setItalic(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setUnderline() {
+        this.config = SF.setUnderline(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setStrikethrough() {
+        this.config = SF.setStrikethrough(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setBold() {
+        this.config = SF.setBold(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setObfuscated() {
+        this.config = SF.setObfuscated(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerBase setShadow() {
+        this.shadow = true;
+        return this;
+    }
+
+    public abstract void call(@NotNull FontRenderer fontRenderer);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerConstrainedBase.java b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerConstrainedBase.java
new file mode 100644
index 000000000..2abb11678
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/render/font/renderhelper/RenderIntegerConstrainedBase.java
@@ -0,0 +1,110 @@
+package net.minecraft.client.render.font.renderhelper;
+
+import net.minecraft.client.render.font.Alignment;
+import net.minecraft.client.render.font.SF;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.tessellator.Tessellator;
+import net.minecraft.core.util.helper.Color;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("unused")
+public abstract class RenderIntegerConstrainedBase {
+    protected @NotNull Tessellator tessellator;
+    protected @NotNull CharSequence chars;
+    protected int x;
+    protected int y;
+    protected double z;
+    protected int maxWidth;
+    protected int maxHeight;
+    protected double @Nullable [] xPosBuffer;
+    protected double @Nullable [] yPosBuffer;
+    protected long @Nullable [] configBuffer;
+    protected @NotNull Alignment alignment;
+    protected long config;
+    protected boolean shadow;
+    RenderIntegerConstrainedBase() {
+
+    }
+
+    public @NotNull RenderIntegerConstrainedBase init(@NotNull final Tessellator tessellator, @NotNull final CharSequence chars, final int x, final int y, final int maxWidth, final int maxHeight, final double @Nullable [] xPosBuffer, final double @Nullable [] yPosBuffer, final long @Nullable [] configBuffer) {
+        this.tessellator = tessellator;
+        this.chars = chars;
+        this.x = x;
+        this.y = y;
+        this.z = 0;
+        this.maxWidth = maxWidth;
+        this.maxHeight = maxHeight;
+        this.xPosBuffer = xPosBuffer;
+        this.yPosBuffer = yPosBuffer;
+        this.configBuffer = configBuffer;
+        this.alignment = Alignment.LEFT;
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setConfig(final long config) {
+        this.config = config;
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase resetConfig() {
+        this.config = FontHelper.CONFIG_DEFAULT;
+        this.shadow = false;
+        this.z = 0;
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setZ(final double zLevel) {
+        this.z = zLevel;
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setColor(final @NotNull Color color) {
+        this.config = SF.setColor(this.config, color.value);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setColor(final int argb) {
+        this.config = SF.setColor(this.config, argb);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setItalic() {
+        this.config = SF.setItalic(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setUnderline() {
+        this.config = SF.setUnderline(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setStrikethrough() {
+        this.config = SF.setStrikethrough(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setBold() {
+        this.config = SF.setBold(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setObfuscated() {
+        this.config = SF.setObfuscated(this.config);
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setShadow() {
+        this.shadow = true;
+        return this;
+    }
+
+    public @NotNull RenderIntegerConstrainedBase setAlignment(@NotNull final Alignment alignment) {
+        this.alignment = alignment;
+        return this;
+    }
+
+    public abstract void call(@NotNull FontRenderer fontRenderer);
+}
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
index 3c7ccd1d6..9e833c112 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModel.java
@@ -1,10 +1,9 @@
 package net.minecraft.client.render.item.model;
 
 import net.minecraft.client.render.EntityRenderDispatcher;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.ItemRenderer;
-import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
@@ -25,7 +24,7 @@ public abstract class ItemModel {
     }
 
     public abstract void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX); // TODO figure out if theres a way to not explicitly need to mirrorX in the model itself
-    public abstract void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha);
+    public abstract void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull FontRenderer fontRenderer, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha);
 
     public void renderGui(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, int x, int y, float brightness, float alpha, float partialTick) {
         GL11.glPushMatrix();
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
index 156213958..2587cc04a 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelNone.java
@@ -1,7 +1,7 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.entity.Entity;
@@ -16,17 +16,17 @@ public class ItemModelNone extends ItemModel{
 
 
     @Override
-    public void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX) {
+    public void render(@NotNull final Tessellator tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, final float brightness, final float alpha, final float partialTick, final boolean mirrorX) {
 
     }
 
     @Override
-    public void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha) {
+    public void renderItemOverlayIntoGUI(@NotNull final Tessellator tessellator, @NotNull final FontRenderer fontRenderer, @NotNull final TextureManager textureManager, @NotNull final ItemStack itemstack, final int x, final int y, @Nullable final String override, final float alpha) {
 
     }
 
     @Override
-    public IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack) {
+    public IconCoordinate getIcon(@Nullable final Entity entity, final ItemStack itemStack) {
         return null;
     }
 }
diff --git a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
index 4437d04bb..998a80791 100644
--- a/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
+++ b/game/client/src/main/java/net/minecraft/client/render/item/model/ItemModelStandard.java
@@ -1,7 +1,8 @@
 package net.minecraft.client.render.item.model;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
 import net.minecraft.client.render.tessellator.Tessellator;
@@ -45,39 +46,39 @@ public class ItemModelStandard extends ItemModel{
 
     protected boolean itemfullBright = false;
 
-    public ItemModelStandard(Item item, String namespace) {
+    public ItemModelStandard(final Item item, final String namespace) {
         super(item);
-        displayPosMap.put(DisplayPos.GROUND, DEFAULT_ITEM_GROUND);
-        displayPosMap.put(DisplayPos.HEAD, DEFAULT_ITEM_HEAD);
-        displayPosMap.put(DisplayPos.THIRD_PERSON_RIGHT_HAND, DEFAULT_ITEM_THIRD_PERSON_RIGHT_HAND);
-        displayPosMap.put(DisplayPos.THIRD_PERSON_LEFT_HAND, DEFAULT_ITEM_THIRD_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
-        displayPosMap.put(DisplayPos.FIRST_PERSON_RIGHT_HAND, DEFAULT_ITEM_FIRST_PERSON_RIGHT_HAND);
-        displayPosMap.put(DisplayPos.FIRST_PERSON_LEFT_HAND, DEFAULT_ITEM_FIRST_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
-        displayPosMap.put(DisplayPos.FIXED, DEFAULT_ITEM_FIXED);
+        this.displayPosMap.put(DisplayPos.GROUND, DEFAULT_ITEM_GROUND);
+        this.displayPosMap.put(DisplayPos.HEAD, DEFAULT_ITEM_HEAD);
+        this.displayPosMap.put(DisplayPos.THIRD_PERSON_RIGHT_HAND, DEFAULT_ITEM_THIRD_PERSON_RIGHT_HAND);
+        this.displayPosMap.put(DisplayPos.THIRD_PERSON_LEFT_HAND, DEFAULT_ITEM_THIRD_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
+        this.displayPosMap.put(DisplayPos.FIRST_PERSON_RIGHT_HAND, DEFAULT_ITEM_FIRST_PERSON_RIGHT_HAND);
+        this.displayPosMap.put(DisplayPos.FIRST_PERSON_LEFT_HAND, DEFAULT_ITEM_FIRST_PERSON_LEFT_HAND); // TODO make automatic since its just the axis flipped
+        this.displayPosMap.put(DisplayPos.FIXED, DEFAULT_ITEM_FIXED);
         if (namespace != null){
-            icon = TextureRegistry.getTexture(namespace + ":item/" + item.getKey().substring("item.".length()).replace(".", "_"));
+            this.icon = TextureRegistry.getTexture(namespace + ":item/" + item.getKey().substring("item.".length()).replace(".", "_"));
         }
     }
 
     @Override
-    public void render(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, @NotNull String displayPosId, boolean items3d, int clusterSize, float brightness, float alpha, float partialTick, boolean mirrorX) {
+    public void render(@NotNull final Tessellator tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, @NotNull final String displayPosId, final boolean items3d, final int clusterSize, final float brightness, final float alpha, final float partialTick, final boolean mirrorX) {
         random.setSeed(187L);
-        DisplayPos displayPos = getDisplayPos(displayPosId);
+        final DisplayPos displayPos = getDisplayPos(displayPosId);
         GL11.glTranslatef(displayPos.tx, displayPos.ty, displayPos.tz);
         GL11.glRotatef(displayPos.rx, 1, 0, 0);
         GL11.glRotatef(displayPos.ry, 0, 1, 0);
         GL11.glRotatef(displayPos.rz, 0, 0, 1);
         GL11.glScalef(displayPos.sx, displayPos.sy, displayPos.sz);
-        int color = getColor(itemStack);
-        float r = net.minecraft.core.util.helper.Color.redFromInt(color)/255f;
-        float g = net.minecraft.core.util.helper.Color.greenFromInt(color)/255f;
-        float b = net.minecraft.core.util.helper.Color.blueFromInt(color)/255f;
+        final int color = getColor(itemStack);
+        final float r = net.minecraft.core.util.helper.Color.redFromInt(color)/255f;
+        final float g = net.minecraft.core.util.helper.Color.greenFromInt(color)/255f;
+        final float b = net.minecraft.core.util.helper.Color.blueFromInt(color)/255f;
         GL11.glColor4f(brightness * r, brightness * g, brightness * b, alpha);
         if (items3d) {
             for (int i = 0; i < clusterSize; i++) {
-                float offX = 0;
-                float offY = 0;
-                float offZ = 0.1f * i;
+                final float offX = 0;
+                final float offY = 0;
+                final float offZ = 0.1f * i;
                 GL11.glTranslatef(offX, offY, offZ);
                 renderSingle(tessellator, holder, itemStack, true, brightness, alpha, partialTick, mirrorX);
                 GL11.glTranslatef(-offX, -offY, -offZ);
@@ -99,11 +100,11 @@ public class ItemModelStandard extends ItemModel{
         }
     }
 
-    protected void renderSingle(@NotNull Tessellator tessellator, @Nullable Entity holder, @NotNull ItemStack itemStack, boolean items3d, float brightness, float alpha, float partialTick, boolean mirrorX) {
+    protected void renderSingle(@NotNull final Tessellator tessellator, @Nullable final Entity holder, @NotNull final ItemStack itemStack, final boolean items3d, final float brightness, final float alpha, final float partialTick, final boolean mirrorX) {
         renderCoordinate(tessellator, getIcon(holder, itemStack), items3d, mirrorX);
     }
 
-    protected void renderCoordinate(@NotNull Tessellator tessellator, @NotNull IconCoordinate coordinate, boolean items3d, boolean mirrorX) {
+    protected void renderCoordinate(@NotNull final Tessellator tessellator, @NotNull final IconCoordinate coordinate, final boolean items3d, final boolean mirrorX) {
         final double cUMin = mirrorX ? coordinate.getIconUMax() : coordinate.getIconUMin();
         final double cUMax = mirrorX ? coordinate.getIconUMin() : coordinate.getIconUMax();
         final double cVMin = coordinate.getIconVMin();
@@ -125,10 +126,10 @@ public class ItemModelStandard extends ItemModel{
 
             // top bottom
             for (int h = 0; h < pxH; h++) {
-                double y1 = (double) h /pxH;
-                double y2 = (double) (h + 1) /pxH;
-                double vMin = coordinate.getSubIconV(y1);
-                double vMax = coordinate.getSubIconV(y2);
+                final double y1 = (double) h /pxH;
+                final double y2 = (double) (h + 1) /pxH;
+                final double vMin = coordinate.getSubIconV(y1);
+                final double vMax = coordinate.getSubIconV(y2);
 
                 // top
                 tessellator.setNormal(0, 1, 0);
@@ -147,12 +148,12 @@ public class ItemModelStandard extends ItemModel{
 
             // left right
             for (int w = 0; w < pxW; w++) {
-                double x1 = (double) w / pxW;
-                double x2 = (double) (w + 1) / pxW;
+                final double x1 = (double) w / pxW;
+                final double x2 = (double) (w + 1) / pxW;
 
 
-                double uMin = coordinate.getSubIconU(mirrorX ? 1 - x1 : x1);
-                double uMax = coordinate.getSubIconU(mirrorX ? 1 - x2 : x2);
+                final double uMin = coordinate.getSubIconU(mirrorX ? 1 - x1 : x1);
+                final double uMax = coordinate.getSubIconU(mirrorX ? 1 - x2 : x2);
 
                 // right
                 tessellator.setNormal(-1, 0, 0);
@@ -191,25 +192,25 @@ public class ItemModelStandard extends ItemModel{
         }
     }
 
-    public @NotNull DisplayPos getDisplayPos(@NotNull String id) {
-        return displayPosMap.getOrDefault(id, DisplayPos.DEFAULT_DISPLAY_POS);
+    public @NotNull DisplayPos getDisplayPos(@NotNull final String id) {
+        return this.displayPosMap.getOrDefault(id, DisplayPos.DEFAULT_DISPLAY_POS);
     }
 
-    public @NotNull ItemModelStandard setDisplayPos(@NotNull String id, @NotNull DisplayPos displayPos) {
+    public @NotNull ItemModelStandard setDisplayPos(@NotNull final String id, @NotNull final DisplayPos displayPos) {
         this.displayPosMap.put(id, Objects.requireNonNull(displayPos, "Display pos cannot be null!"));
         return this;
     }
 
     @Override
-    public void renderItemOverlayIntoGUI(@NotNull Tessellator tessellator, @NotNull Font font, @NotNull TextureManager textureManager, @NotNull ItemStack itemstack, int x, int y, @Nullable String override, float alpha) {
+    public void renderItemOverlayIntoGUI(@NotNull final Tessellator tessellator, @NotNull final FontRenderer fontRenderer, @NotNull final TextureManager textureManager, @NotNull final ItemStack itemstack, final int x, final int y, @Nullable final String override, final float alpha) {
         glEnable(GL_BLEND);
         glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
         final int a = (int) (alpha * 255.0f);
         if (itemstack.stackSize != 1 || override != null) {
-            String s = override != null ? override : "" + itemstack.stackSize;
+            final String s = override != null ? override : "" + itemstack.stackSize;
             GL11.glDisable(GL_LIGHTING);
             GL11.glDisable(GL_DEPTH_TEST);
-            font.drawStringWithShadow(s, (x + 19) - 2 - font.getStringWidth(s), y + 6 + 3, 0xffffff | (a << 24));
+            FontHelper.render(tessellator, s, (x + 19) - 2 - fontRenderer.stringWidth(s), y + 6 + 3).setShadow().setColor(0xffffff | (a << 24)).call(fontRenderer);
             GL11.glEnable(GL_LIGHTING);
             GL11.glEnable(GL_DEPTH_TEST);
         }
@@ -232,7 +233,7 @@ public class ItemModelStandard extends ItemModel{
         glDisable(GL_BLEND);
     }
 
-    protected void renderColoredQuad(Tessellator tessellator, int x, int y, int width, int height, int colorRGB, int alpha) {
+    protected void renderColoredQuad(final Tessellator tessellator, final int x, final int y, final int width, final int height, final int colorRGB, final int alpha) {
         final float z = 0.0F;
         tessellator.startDrawingQuads();
         tessellator.setColorRGBA_I(colorRGB, alpha);
@@ -243,21 +244,21 @@ public class ItemModelStandard extends ItemModel{
         tessellator.draw();
     }
 
-    public @NotNull IconCoordinate getIcon(@Nullable Entity entity, ItemStack itemStack){
-        return icon;
+    public @NotNull IconCoordinate getIcon(@Nullable final Entity entity, final ItemStack itemStack){
+        return this.icon;
     }
-    public int getColor(ItemStack stack)
+    public int getColor(final ItemStack stack)
     {
         return getColorFromMeta(stack.getMetadata());
     }
-    public int getColorFromMeta(int meta)
+    public int getColorFromMeta(final int meta)
     {
         return 0xffffff;
     }
 
     public ItemModelStandard setFullBright()
     {
-        itemfullBright = true;
+        this.itemfullBright = true;
         return this;
     }
 }
\ No newline at end of file
diff --git a/game/client/src/main/java/net/minecraft/client/render/texture/TextureFile.java b/game/client/src/main/java/net/minecraft/client/render/texture/TextureFile.java
index b8a437c3f..ee65211e2 100644
--- a/game/client/src/main/java/net/minecraft/client/render/texture/TextureFile.java
+++ b/game/client/src/main/java/net/minecraft/client/render/texture/TextureFile.java
@@ -23,63 +23,70 @@ public class TextureFile extends Texture{
         this.sourcePath = null;
     }
 
-    public TextureFile(String path) {
+    public TextureFile(final String path) {
         generate();
         this.sourcePath = path;
-        init();
     }
 
     @Override
-    public boolean hasMeta(String key) {
-        return metaHandler.has(key);
+    public boolean hasMeta(final String key) {
+        return this.metaHandler.has(key);
     }
 
     @Override
-    public @Nullable <T> T getMeta(String key, Class<T> aClass) {
-        return metaHandler.get(key, aClass);
+    public @Nullable <T> T getMeta(final String key, final Class<T> aClass) {
+        return this.metaHandler.get(key, aClass);
     }
 
     @Override
-    public <T> T getOrDefaultMeta(String key, T metaDefault, Class<T> aClass) {
-        return metaHandler.getOrDefault(key, metaDefault, aClass);
+    public <T> T getOrDefaultMeta(final String key, final T metaDefault, final Class<T> aClass) {
+        return this.metaHandler.getOrDefault(key, metaDefault, aClass);
     }
 
     @Override
     public void init() {
-        metaHandler.reset();
+        initFileTex(true);
+    }
+
+    public boolean initFileTex(final boolean defaultMissingTex) {
+        this.metaHandler.reset();
 
-        if (sourcePath != null) {
-            Minecraft mc = Minecraft.getMinecraft();
-            TexturePack pack = mc.texturePackList.getHighestPriorityTexturePackWithFile(sourcePath);
+        if (this.sourcePath != null) {
+            final Minecraft mc = Minecraft.getMinecraft();
+            final TexturePack pack = mc.texturePackList.getHighestPriorityTexturePackWithFile(this.sourcePath);
             if (pack == null) {
-                setupTexture(missingTexture);
-                return;
+                if (defaultMissingTex) setupTexture(missingTexture);
+                return false;
             }
 
-            try (InputStream stream = pack.getResourceAsStream(sourcePath + ".mcmeta")) {
+            try (final InputStream stream = pack.getResourceAsStream(this.sourcePath + ".mcmeta")) {
                 if (stream != null) {
-                    metaHandler.loadFromStream(stream);
+                    this.metaHandler.loadFromStream(stream);
                 }
-            } catch (Exception e) {
-                LOGGER.error("Failed to load data for '{}.mcmeta'!", sourcePath, e);
+            } catch (final Exception e) {
+                LOGGER.error("Failed to load data for '{}.mcmeta'!", this.sourcePath, e);
             }
 
-            try (InputStream imageStream = pack.getResourceAsStream(sourcePath)) {
+            try (final InputStream imageStream = pack.getResourceAsStream(this.sourcePath)) {
                 if (imageStream == null) {
-                    setupTexture(missingTexture);
-                    return;
+                    if (defaultMissingTex) setupTexture(missingTexture);
+                    return false;
                 }
                 setupTexture(readImage(imageStream));
-            } catch (IOException e) {
-                setupTexture(missingTexture);
+            } catch (final IOException e) {
+                if (defaultMissingTex) setupTexture(missingTexture);
+                return false;
             }
+        } else {
+            return false;
         }
+        return true;
     }
 
     @Override
     public String toString() {
-        return "Source: " + sourcePath + "\n" +
-                "Meta: \n" + metaHandler;
+        return "Source: " + this.sourcePath + "\n" +
+                "Meta: \n" + this.metaHandler;
     }
 
 }
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 6e3a23f1b..119be40f2 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
@@ -4,7 +4,6 @@ import com.mojang.logging.LogUtils;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.TooltipElement;
 import net.minecraft.client.gui.keyboard.KeyboardLayout;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
 import net.minecraft.client.sound.SoundRepository;
@@ -35,13 +34,16 @@ public class TexturePackList
 	public TexturePackList(Minecraft minecraft, File file) {
 		this.mc = minecraft;
 
-		texturePackDir = new File(file, "texturepacks");
-		if(!texturePackDir.exists()) {
-			texturePackDir.mkdirs();
+        this.texturePackDir = new File(file, "texturepacks");
+		if(!this.texturePackDir.exists()) {
+            this.texturePackDir.mkdirs();
 		}
+	}
 
+	public void init() {
 		updateAvailableTexturePacks();
 	}
+
 	public void shiftPack(TexturePack pack, int shiftAmount){
 		if (!selectedPacks.contains(pack)) return;
 		if (shiftAmount == 0) return;
@@ -93,7 +95,6 @@ public class TexturePackList
 	}
 	public void refresh(){
 		mc.textureManager.refreshTexturesAndDisplayErrors();
-		mc.font = new Font(mc, mc.gameSettings, mc.textureManager);
 		mc.renderGlobal.loadRenderers();
 		if (mc.currentScreen != null) {
 			mc.currentScreen.updateFont();
@@ -231,6 +232,13 @@ public class TexturePackList
 		return selectedPacks.get(selectedPacks.size()-1);
 	}
 
+	public boolean anyHasFile(String path) {
+		for (int i = 0; i < this.selectedPacks.size(); i++) {
+			if (this.selectedPacks.get(i).hasFile(path)) return true;
+		}
+		return false;
+	}
+
 	public @Nullable TexturePack getHighestPriorityTexturePackWithFile(String path) {
 		return getHighestPriorityTexturePackWithFile(path, true);
 	}
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
index 4d41ee199..4bb35ed7d 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRenderer.java
@@ -1,8 +1,8 @@
 package net.minecraft.client.render.tileentity;
 
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.TileEntityRenderDispatcher;
+import net.minecraft.client.render.font.FontRenderer;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.world.World;
@@ -33,7 +33,7 @@ public abstract class TileEntityRenderer<T extends TileEntity>
     }
 
 
-    public Font getFont()
+    public FontRenderer getFont()
     {
         return renderDispatcher.getFont();
     }
diff --git a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
index bfdb6820e..bd6b3d8ea 100644
--- a/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
+++ b/game/client/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererSign.java
@@ -1,12 +1,10 @@
 package net.minecraft.client.render.tileentity;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.LightmapHelper;
-import net.minecraft.client.render.model.ModelBase;
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.client.render.model.ModelSign;
-import net.minecraft.client.render.model.ModelSkeleton;
-import net.minecraft.client.render.model.ModelZombie;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.client.render.texture.stitcher.IconCoordinate;
 import net.minecraft.client.render.texture.stitcher.TextureRegistry;
@@ -31,7 +29,7 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
     }
 
      @Override
-	public void doRender(Tessellator tessellator, TileEntitySign tileEntity, double x, double y, double z,
+	public void doRender(Tessellator t, TileEntitySign tileEntity, double x, double y, double z,
                          float partialTick)
     {
         Block<?> block = tileEntity.getBlock();
@@ -82,7 +80,7 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
         GL11.glPopMatrix();
 
         // Render text
-        Font font = getFont();
+        FontRenderer sr = getFont();
         float lightLevel = LightmapHelper.isLightmapEnabled() ? 1 : mc.currentWorld.getLightBrightness(tileEntity.x, tileEntity.y, tileEntity.z);
         float lightOffset = 0f;
         if (tileEntity.isGlowing()) {
@@ -111,7 +109,7 @@ public class TileEntityRendererSign extends TileEntityRenderer<TileEntitySign>
             {
                 text = "> " + text + " <";
             }
-            font.drawString(text, -font.getStringWidth(text) / 2, line * 10 - tileEntity.signText.length * 5, color);
+            FontHelper.render(t, text, -sr.stringWidth(text) / 2, line * 10 - tileEntity.signText.length * 5).setColor(color).call(sr);
         }
         GL11.glPopMatrix();
 
diff --git a/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java b/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java
index 8211407a3..e70b289c2 100644
--- a/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java
+++ b/game/client/src/main/java/net/minecraft/client/util/debug/DebugRender.java
@@ -2,12 +2,13 @@ package net.minecraft.client.util.debug;
 
 import static org.lwjgl.opengl.GL11.*;
 
+import net.minecraft.client.render.font.FontRenderer;
+import net.minecraft.client.render.font.renderhelper.FontHelper;
 import net.minecraft.core.util.debug.Debug;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.Display;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.render.Font;
 import net.minecraft.client.render.tessellator.Tessellator;
 import net.minecraft.core.util.debug.Debug.Profiler;
 import net.minecraft.core.util.helper.MathHelper;
@@ -65,7 +66,7 @@ public class DebugRender {
 		resetFrametimes();
 	}
 	
-	public static void render(Font font) {
+	public static void render(FontRenderer sr) {
 		frametimes[pos] = selectedProfiler.time;
 		baseframetimes[pos] = Debug.baseProfiler.time;
 		pos++;
@@ -89,18 +90,18 @@ public class DebugRender {
 		glEnable(GL_BLEND);
 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 		
-		Tessellator tessellator = Tessellator.instance;
+		Tessellator t = Tessellator.instance;
 		
 		int x = w - frametimes.length;
 		int y = h;
 		
 		if(selectedProfiler != Debug.baseProfiler) {
 			if(w > frametimes.length + baseframetimes.length) {
-				drawFrameTimes(tessellator, x, y, baseframetimes);
+				drawFrameTimes(t, x, y, baseframetimes);
 			}
-			drawFrameTimes(tessellator, 0, y, frametimes);
+			drawFrameTimes(t, 0, y, frametimes);
 		}else {
-			drawFrameTimes(tessellator, 0, y, baseframetimes);
+			drawFrameTimes(t, 0, y, baseframetimes);
 		}
 
 		glDisable(GL_BLEND);
@@ -118,10 +119,10 @@ public class DebugRender {
 		
 		int fps = Debug.getFps();
 		if(fps >= 0) {
-			font.drawString("fps: " + fps, x1, y1 - 2 * lineHeight, 0xFFFFFFFF);
+			FontHelper.render(t, "fps: " + fps, x1, y1 - 2 * lineHeight).call(sr);
 		}
-		font.drawString("avg: " + (getAvgTime(frametimes) / 1000.0) + " ms", x1, y1 - lineHeight, 0xFFFFFFFF);
-		font.drawString(selectedProfiler.name + ": ", x1, y1, 0xFFFFFFFF);
+		FontHelper.render(t, "avg: " + (getAvgTime(frametimes) / 1000.0) + " ms", x1, y1 - lineHeight).call(sr);
+		FontHelper.render(t, selectedProfiler.name + ": ", x1, y1).call(sr);
 		for(int i=0; i < selectedProfiler.allProfilers.size(); i++) {
 			Profiler profiler = selectedProfiler.allProfilers.get(i);
 
@@ -129,7 +130,7 @@ public class DebugRender {
 			if(i == selection) {
 				color = 0xFF00FFFF;
 			}
-			font.drawString(i + ": " + profiler.name, x1, y1 + (i + 1) * lineHeight, color);
+			FontHelper.render(t, i + ": " + profiler.name, x1, y1 + (i + 1) * lineHeight).setColor(color).call(sr);
 		}
 		glEnable(GL_ALPHA_TEST);
 	}
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/border.png b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/border.png
index fa2ee3da4..088c5f1eb 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/border.png and b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/border.png differ
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/properties.json b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/properties.json
new file mode 100644
index 000000000..c7c934cdf
--- /dev/null
+++ b/game/client/src/main/resources/assets/minecraft/textures/gui/sprites/tooltip/default/properties.json
@@ -0,0 +1,3 @@
+{
+    "padding": 0
+}
\ No newline at end of file
diff --git a/game/client/src/test/java/TestItemModelDispatcher.java b/game/client/src/test/java/TestItemModelDispatcher.java
index d976a6a88..c779d6c07 100644
--- a/game/client/src/test/java/TestItemModelDispatcher.java
+++ b/game/client/src/test/java/TestItemModelDispatcher.java
@@ -1,9 +1,5 @@
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.option.GameSettings;
-import net.minecraft.client.render.Font;
-import net.minecraft.client.render.TextureManager;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
-import net.minecraft.client.render.texturepack.TexturePackList;
 import net.minecraft.client.util.helper.Colors;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.item.Item;
@@ -25,11 +21,7 @@ public class TestItemModelDispatcher {
         Colors.loadDummyColors();
 
         // Map model requires mc font reference
-        Minecraft mc = new Minecraft(null,true);
-        mc.gameSettings = new GameSettings(mc, mc.getMinecraftDir());
-        mc.texturePackList = new TexturePackList(mc, mc.getMinecraftDir());
-        mc.textureManager = new TextureManager(mc, mc.texturePackList, mc.gameSettings);
-        mc.font = new Font(mc, mc.gameSettings, mc.textureManager);
+        new Minecraft(Minecraft.getAppDir("minecraft-bta"), null,true);
 
         for (Map.Entry<NamespaceID, Item> e : Item.itemsMap.entrySet()) {
             Assertions.assertTrue(ItemModelDispatcher.getInstance().hasDispatch(e.getValue()), () -> "Item '" + e.getKey() + "' is not assigned a item model!");
diff --git a/game/core/src/main/java/net/minecraft/core/lang/text/Text.java b/game/core/src/main/java/net/minecraft/core/lang/text/Text.java
index d5dfcc64e..fef4477b0 100644
--- a/game/core/src/main/java/net/minecraft/core/lang/text/Text.java
+++ b/game/core/src/main/java/net/minecraft/core/lang/text/Text.java
@@ -1,8 +1,9 @@
 package net.minecraft.core.lang.text;
 
 import net.minecraft.core.net.command.TextFormatting;
+import org.jetbrains.annotations.NotNull;
 
-public abstract class Text {
+public abstract class Text implements CharSequence {
     public static Text text() {
         return new ChainText();
     }
@@ -35,4 +36,21 @@ public abstract class Text {
     public Text fmt(TextFormatting formatting, Text text) {
         return new ChainText(this, new FormattedText(formatting, text));
     }
+
+    // TODO consider a more optimized implementation if we keep this as a char sequence
+    @Override
+    public int length() {
+        return toString().length();
+    }
+
+    @Override
+    public char charAt(int index) {
+        return toString().charAt(index);
+    }
+
+    @NotNull
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return toString().subSequence(start, end);
+    }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/lang/text/TranslatableText.java b/game/core/src/main/java/net/minecraft/core/lang/text/TranslatableText.java
index a9ad41fd6..b3da433ad 100644
--- a/game/core/src/main/java/net/minecraft/core/lang/text/TranslatableText.java
+++ b/game/core/src/main/java/net/minecraft/core/lang/text/TranslatableText.java
@@ -14,4 +14,5 @@ public class TranslatableText
     void toString(StringBuilder sb) {
         sb.append(I18n.getInstance().translateKey(languageKey));
     }
+
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/ChatLine.java b/game/core/src/main/java/net/minecraft/core/net/ChatLine.java
index 9a89e1b17..aebf3420a 100644
--- a/game/core/src/main/java/net/minecraft/core/net/ChatLine.java
+++ b/game/core/src/main/java/net/minecraft/core/net/ChatLine.java
@@ -4,12 +4,12 @@ package net.minecraft.core.net;
 public class ChatLine
 {
 
-    public ChatLine(String s)
+    public ChatLine(CharSequence s)
     {
         message = s;
         updateCounter = 0;
     }
 
-    public String message;
+    public CharSequence message;
     public int updateCounter;
 }
diff --git a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
index 3da062e97..0a1236020 100644
--- a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
+++ b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java
@@ -3,7 +3,9 @@ package net.minecraft.core.net.command;
 import org.jetbrains.annotations.Nullable;
 
 public class TextFormatting {
-	public static final TextFormatting[] FORMATTINGS = new TextFormatting[22];
+	public static final String FORMAT_CHARS = "0123456789abcdefklmnor+-";
+	public static final String FORMAT_REGEX = "§[0123456789abcdefklmnor+-]|§<(.*?)>";
+	public static final TextFormatting[] FORMATTINGS = new TextFormatting[24];
 	
 	public static final TextFormatting WHITE = new TextFormatting(0).setNames("White");
 	public static final TextFormatting ORANGE = new TextFormatting(1).setNames("Orange");
@@ -27,6 +29,8 @@ public class TextFormatting {
     public static final TextFormatting UNDERLINE = new TextFormatting(19).setNames("Underline");
     public static final TextFormatting ITALIC = new TextFormatting(20).setNames("Italic");
     public static final TextFormatting RESET = new TextFormatting(21).setNames("Reset");
+    public static final TextFormatting PUSH = new TextFormatting(22).setNames("Push");
+    public static final TextFormatting POP = new TextFormatting(23).setNames("Pop");
 
 	public static final char SPECIAL_CHAR = '\247';
 
@@ -37,7 +41,7 @@ public class TextFormatting {
 	public TextFormatting(int id) {
 		FORMATTINGS[id] = this;
 		this.id = id;
-		this.code = "0123456789abcdefklmnor".charAt(id);
+		this.code = FORMAT_CHARS.charAt(id);
 	}
 
 	public static @Nullable TextFormatting fromChar(final char c) {
@@ -66,7 +70,7 @@ public class TextFormatting {
 		return null;
 	}
 	public static String removeAllFormatting(String name){
-		return name.replaceAll("§[0123456789abcdefklmnor]|§<(.*?)>", "");
+		return name.replaceAll(FORMAT_REGEX, "");
 	}
 
     public static String formatted(String string, TextFormatting... formattings) {
diff --git a/game/core/src/main/resources/lang/en_US/gui.lang b/game/core/src/main/resources/lang/en_US/gui.lang
index 86f765de1..bc079d09f 100644
--- a/game/core/src/main/resources/lang/en_US/gui.lang
+++ b/game/core/src/main/resources/lang/en_US/gui.lang
@@ -242,6 +242,7 @@ gui.options.page.debug.button.open.biome_finder=Open Seed Viewer
 gui.options.page.debug.button.open.datadumper=Run Data Dumper
 gui.options.page.debug.button.open.sound_test=Open Sound Test
 gui.options.page.debug.button.open.texture_viewer=Open Texture Viewer
+gui.options.page.debug.button.open.font_tester=Open Font Test
 gui.options.page.debug.button.open.achievements=Open Achievements
 gui.options.page.debug.button.wipestats=Delete Stats
 gui.options.page.debug.button.unlockedall=Unlock all stats
