diff --git a/dependencies/symbol-processor/src b/dependencies/symbol-processor/src
index 95e24d13fa..fbdd1e2798 160000
--- a/dependencies/symbol-processor/src
+++ b/dependencies/symbol-processor/src
@@ -1 +1 @@
-Subproject commit 95e24d13fa223ff524f8920314c4984686c73928
+Subproject commit fbdd1e27983eeb1329d51ee3264b2974c4901fbe
diff --git a/media-layer/core/src/media.c b/media-layer/core/src/media.c
index 759c01ef89..68c5fd6b58 100644
--- a/media-layer/core/src/media.c
+++ b/media-layer/core/src/media.c
@@ -219,7 +219,7 @@ static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int c
         memset(str, 0, str_size);
         codepoint_to_utf8((unsigned char *) str, codepoint);
         char *cp437_str = to_cp437(str);
-        // Send EventĀ·
+        // Send Event
         for (int i = 0; cp437_str[i] != '\0'; i++) {
             character_event(cp437_str[i]);
         }
diff --git a/mods/include/mods/text-input-box/TextInputBox.h b/mods/include/mods/text-input-box/TextInputBox.h
index 2f3410bcb8..16f62bfee7 100644
--- a/mods/include/mods/text-input-box/TextInputBox.h
+++ b/mods/include/mods/text-input-box/TextInputBox.h
@@ -3,22 +3,9 @@
 #include <symbols/minecraft.h>
 
 struct TextInputBox {
-    GuiComponent super;
+    static TextInputBox *create(const std::string &placeholder = "", const std::string &text = "");
 
-    int m_ID;
-    int m_xPos;
-    int m_yPos;
-    int m_width;
-    int m_height;
-    std::string m_placeholder;
-    std::string m_text;
-    bool m_bFocused;
-    bool m_bEnabled;
-    bool m_bCursorOn;
-    int m_insertHead;
-    int m_lastFlashed;
-    Font *m_pFont;
-    int m_maxLength;
+    GuiComponent super;
 
     void setSize(int x, int y, int width = 200, int height = 12);
     void init(Font *pFont);
@@ -30,6 +17,25 @@ struct TextInputBox {
     void setFocused(bool b);
     void onClick(int x, int y);
     bool clicked(int x, int y);
+    std::string getText();
+    bool isFocused();
+    void setMaxLength(int max_length);
 
-    static TextInputBox *create(int id, const std::string &placeholder = "", const std::string &text = "");
+private:
+    void recalculateScroll();
+
+    std::string m_text;
+    bool m_bFocused;
+    int m_xPos;
+    int m_yPos;
+    int m_width;
+    int m_height;
+    std::string m_placeholder;
+    bool m_bEnabled;
+    bool m_bCursorOn;
+    int m_insertHead;
+    int m_lastFlashed;
+    Font *m_pFont;
+    int m_maxLength;
+    int m_scrollPos;
 };
diff --git a/mods/include/mods/touch/touch.h b/mods/include/mods/touch/touch.h
new file mode 100644
index 0000000000..e375b4c0ff
--- /dev/null
+++ b/mods/include/mods/touch/touch.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <symbols/minecraft.h>
+
+Button *touch_create_button(int id, std::string text);
diff --git a/mods/src/chat/chat-internal.h b/mods/src/chat/chat-internal.h
index 293c6a0f03..128e478038 100644
--- a/mods/src/chat/chat-internal.h
+++ b/mods/src/chat/chat-internal.h
@@ -1,19 +1,21 @@
 #pragma once
 
+#include <string>
+
 #include <libreborn/libreborn.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+// Message Limitations
+#define MAX_CHAT_MESSAGE_LENGTH 256
 
+// Message Prefix
+__attribute__((visibility("internal"))) std::string _chat_get_prefix(char *username);
+
+// Queue Message For Sending
 #ifndef MCPI_SERVER_MODE
 __attribute__((visibility("internal"))) void _chat_queue_message(const char *message);
 #endif
 
+// Init Chat UI
 #ifndef MCPI_HEADLESS_MODE
 __attribute__((visibility("internal"))) void _init_chat_ui();
 #endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp
index 1fef0d43d0..563d670ade 100644
--- a/mods/src/chat/chat.cpp
+++ b/mods/src/chat/chat.cpp
@@ -19,9 +19,6 @@
 #include "chat-internal.h"
 #include <mods/chat/chat.h>
 
-// Message Limitations
-#define MAX_CHAT_MESSAGE_LENGTH 512
-
 // Send API Command
 std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
     struct ConnectedClient client;
@@ -47,9 +44,12 @@ static void send_api_chat_command(Minecraft *minecraft, char *str) {
 #endif
 
 // Send Message To Players
+std::string _chat_get_prefix(char *username) {
+    return std::string("<") + username + "> ";
+}
 void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, char *username, char *message) {
     char *full_message = NULL;
-    safe_asprintf(&full_message, "<%s> %s", username, message);
+    safe_asprintf(&full_message, "%s%s", _chat_get_prefix(username).c_str(), message);
     sanitize_string(&full_message, MAX_CHAT_MESSAGE_LENGTH, 0);
     std::string cpp_string = full_message;
     free(full_message);
@@ -123,5 +123,8 @@ void init_chat() {
         // Init UI
         _init_chat_ui();
 #endif
+        // Disable Built-In Chat Message Limiting
+        unsigned char message_limit_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r4, r4"
+        patch((void *) 0x6b4c0, message_limit_patch);
     }
 }
diff --git a/mods/src/chat/ui.cpp b/mods/src/chat/ui.cpp
index c7d600010c..274e2d364a 100644
--- a/mods/src/chat/ui.cpp
+++ b/mods/src/chat/ui.cpp
@@ -8,6 +8,7 @@
 #include <mods/chat/chat.h>
 #include <mods/text-input-box/TextInputScreen.h>
 #include <mods/misc/misc.h>
+#include <mods/touch/touch.h>
 
 // Structure
 struct ChatScreen {
@@ -23,24 +24,16 @@ CUSTOM_VTABLE(chat_screen, Screen) {
         original_init(super);
         ChatScreen *self = (ChatScreen *) super;
         // Text Input
-        self->chat = TextInputBox::create(1);
+        self->chat = TextInputBox::create();
         self->super.m_textInputs->push_back(self->chat);
         self->chat->init(super->font);
         self->chat->setFocused(true);
+        // Determien Max Length
+        std::string prefix = _chat_get_prefix(Strings_default_username);
+        int max_length = MAX_CHAT_MESSAGE_LENGTH - prefix.length();
+        self->chat->setMaxLength(max_length);
         // Send Button
-        if (Minecraft_isTouchscreen(super->minecraft)) {
-            self->send = (Button *) new Touch_TButton;
-        } else {
-            self->send = new Button;
-        }
-        ALLOC_CHECK(self->send);
-        int send_id = 2;
-        std::string send_text = "Send";
-        if (Minecraft_isTouchscreen(super->minecraft)) {
-            Touch_TButton_constructor((Touch_TButton *) self->send, send_id, &send_text);
-        } else {
-            Button_constructor(self->send, send_id, &send_text);
-        }
+        self->send = touch_create_button(1, "Send");
         super->rendered_buttons.push_back(self->send);
         super->selectable_buttons.push_back(self->send);
         // Hide Chat Messages
@@ -69,7 +62,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
     vtable->setupPositions = [](Screen *super) {
         Screen_setupPositions_non_virtual(super);
         ChatScreen *self = (ChatScreen *) super;
-        self->send->height = 20;
+        self->send->height = 24;
         self->send->width = 40;
         int x = 0;
         int y = super->height - self->send->height;
@@ -83,9 +76,9 @@ CUSTOM_VTABLE(chat_screen, Screen) {
     vtable->keyPressed = [](Screen *super, int key) {
         // Handle Enter
         ChatScreen *self = (ChatScreen *) super;
-        if (key == 0x0d && self->chat->m_bFocused) {
-            if (self->chat->m_text.length() > 0) {
-                _chat_queue_message(self->chat->m_text.c_str());
+        if (key == 0x0d && self->chat->isFocused()) {
+            if (self->chat->getText().length() > 0) {
+                _chat_queue_message(self->chat->getText().c_str());
             }
             Minecraft_setScreen(super->minecraft, NULL);
         }
diff --git a/mods/src/game-mode/ui.cpp b/mods/src/game-mode/ui.cpp
index e1ceff80cd..14b27d5399 100644
--- a/mods/src/game-mode/ui.cpp
+++ b/mods/src/game-mode/ui.cpp
@@ -4,230 +4,223 @@
 // Game Mode UI Code Is Useless In Headless Mode
 #ifndef MCPI_SERVER_MODE
 
-#include <pthread.h>
-#include <cstring>
-#include <ctime>
 #include <string>
-#include <stdexcept>
+#include <set>
 
 #include <symbols/minecraft.h>
-#include <media-layer/core.h>
 
+#include <mods/text-input-box/TextInputScreen.h>
+#include <mods/touch/touch.h>
 #include "game-mode-internal.h"
 
-// Run Command
-static char *run_command_proper(const char *command[], bool allow_empty) {
-    // Run
-    int return_code;
-    char *output = run_command(command, &return_code, NULL);
+// Strings
+#define GAME_MODE_STR(mode) ("Game Mode: " mode)
+#define SURVIVAL_STR GAME_MODE_STR("Survival")
+#define CREATIVE_STR GAME_MODE_STR("Creative")
 
-    // Handle Message
-    if (output != NULL) {
-        // Check Return Code
-        if (is_exit_status_success(return_code)) {
-            // Remove Ending Newline
-            int length = strlen(output);
-            if (output[length - 1] == '\n') {
-                output[length - 1] = '\0';
-            }
-            length = strlen(output);
-            // Don't Allow Empty Strings
-            if (allow_empty || length > 0) {
-                // Return
-                return output;
-            }
-        }
-        // Free Output
-        free(output);
-    }
-    // Return
-    return !is_exit_status_success(return_code) ? NULL : run_command_proper(command, allow_empty);
-}
-
-// Track Create World State
-static pthread_mutex_t create_world_state_lock = PTHREAD_MUTEX_INITIALIZER;
-typedef enum {
-    DIALOG_CLOSED,
-    DIALOG_OPEN,
-    DIALOG_SUCCESS
-} create_world_state_dialog_t;
-struct create_world_state_t {
-    volatile create_world_state_dialog_t dialog_state = DIALOG_CLOSED;
-    volatile char *name = NULL;
-    volatile int32_t game_mode = 0;
-    volatile int32_t seed = 0;
+// Structure
+struct CreateWorldScreen {
+    TextInputScreen super;
+    TextInputBox *name;
+    TextInputBox *seed;
+    Button *game_mode;
+    Button *create;
+    Button *back;
 };
-static create_world_state_t create_world_state;
-// Destructor
-__attribute__((destructor)) static void _free_create_world_state_name() {
-    free((void *) create_world_state.name);
-}
-
-// Reset State (Assume Lock)
-static void reset_create_world_state() {
-    create_world_state.dialog_state = DIALOG_CLOSED;
-    if (create_world_state.name != NULL) {
-        free((void *) create_world_state.name);
-    }
-    create_world_state.name = NULL;
-    create_world_state.game_mode = 0;
-    create_world_state.seed = 0;
-}
-
-// Chat Thread
-#define DEFAULT_WORLD_NAME "Unnamed world"
-#define DIALOG_TITLE "Create World"
-#define GAME_MODE_DIALOG_SIZE "200"
-static void *create_world_thread(__attribute__((unused)) void *nop) {
-    // Run Dialogs
-    char *world_name = NULL;
-    {
-        // World Name
-        {
-            // Open
-            const char *command[] = {
-                "zenity",
-                "--title", DIALOG_TITLE,
-                "--name", MCPI_APP_ID,
-                "--entry",
-                "--text", "Enter World Name:",
-                "--entry-text", DEFAULT_WORLD_NAME,
-                NULL
-            };
-            char *output = run_command_proper(command, false);
-            // Handle Message
-            if (output != NULL) {
-                // Store
-                world_name = strdup(output);
-                ALLOC_CHECK(world_name);
-                // Free
-                free(output);
-            } else {
-                // Fail
-                goto fail;
-            }
-        }
-
-        // Game Mode
-        int game_mode = 0;
-        {
-            // Open
-            const char *command[] = {
-                "zenity",
-                "--title", DIALOG_TITLE,
-                "--name", MCPI_APP_ID,
-                "--list",
-                "--radiolist",
-                "--width", GAME_MODE_DIALOG_SIZE,
-                "--height", GAME_MODE_DIALOG_SIZE,
-                "--text", "Select Game Mode:",
-                "--column","Selected",
-                "--column", "Name",
-                "TRUE", "Creative",
-                "FALSE", "Survival",
-                NULL
-            };
-            char *output = run_command_proper(command, false);
-            // Handle Message
-            if (output != NULL) {
-                // Store
-                game_mode = strcmp(output, "Creative") == 0;
-                // Free
-                free(output);
-            } else {
-                // Fail
-                goto fail;
-            }
-        }
-
+static void create_world(Minecraft *minecraft, std::string name, bool is_creative, std::string seed);
+CUSTOM_VTABLE(create_world_screen, Screen) {
+    TextInputScreen::setup(vtable);
+    // Constants
+    static int line_height = 8;
+    static int bottom_padding = 4;
+    static int inner_padding = 4;
+    static int description_padding = 4;
+    static int title_padding = 8;
+    // Init
+    static Screen_init_t original_init = vtable->init;
+    vtable->init = [](Screen *super) {
+        original_init(super);
+        CreateWorldScreen *self = (CreateWorldScreen *) super;
+        // Name
+        self->name = TextInputBox::create("World Name", "Unnamed world");
+        self->super.m_textInputs->push_back(self->name);
+        self->name->init(super->font);
+        self->name->setFocused(true);
         // Seed
-        int32_t seed = 0;
- get_seed:
-        {
-            // Open
-            const char *command[] = {
-                "zenity",
-                "--title", DIALOG_TITLE,
-                "--name", MCPI_APP_ID,
-                "--entry",
-                "--only-numerical",
-                "--text", "Enter Seed (Leave Blank For Random):",
-                NULL
-            };
-            char *output = run_command_proper(command, true);
-            // Handle Message
-            if (output != NULL) {
-                // Store
-                bool valid = true;
-                try {
-                    seed = strlen(output) == 0 ? time(NULL) : std::stoi(output);
-                } catch (std::invalid_argument &e) {
-                    // Invalid Seed
-                    WARN("Invalid Seed: %s", output);
-                    valid = false;
-                } catch (std::out_of_range &e) {
-                    // Out-Of-Range Seed
-                    WARN("Seed Out-Of-Range: %s", output);
-                    valid = false;
-                }
-                // Free
-                free(output);
-                // Retry If Invalid
-                if (!valid) {
-                    goto get_seed;
-                }
-            } else {
-                // Fail
-                goto fail;
-            }
+        self->seed = TextInputBox::create("Seed");
+        self->super.m_textInputs->push_back(self->seed);
+        self->seed->init(super->font);
+        self->seed->setFocused(false);
+        // Game Mode
+        self->game_mode = touch_create_button(1, CREATIVE_STR);
+        super->rendered_buttons.push_back(self->game_mode);
+        super->selectable_buttons.push_back(self->game_mode);
+        // Create
+        self->create = touch_create_button(2, "Create");
+        super->rendered_buttons.push_back(self->create);
+        super->selectable_buttons.push_back(self->create);
+        // Back
+        self->back = touch_create_button(3, "Back");
+        super->rendered_buttons.push_back(self->back);
+        super->selectable_buttons.push_back(self->back);
+    };
+    // Removal
+    static Screen_removed_t original_removed = vtable->removed;
+    vtable->removed = [](Screen *super) {
+        original_removed(super);
+        CreateWorldScreen *self = (CreateWorldScreen *) super;
+        delete self->name;
+        delete self->seed;
+        self->game_mode->vtable->destructor_deleting(self->game_mode);
+        self->back->vtable->destructor_deleting(self->back);
+        self->create->vtable->destructor_deleting(self->create);
+    };
+    // Rendering
+    static Screen_render_t original_render = vtable->render;
+    vtable->render = [](Screen *super, int x, int y, float param_1) {
+        // Background
+        super->vtable->renderBackground(super);
+        // Call Original Method
+        original_render(super, x, y, param_1);
+        // Title
+        std::string title = "Create world";
+        Screen_drawCenteredString(super, super->font, &title, super->width / 2, title_padding, 0xffffffff);
+        // Game Mode Description
+        CreateWorldScreen *self = (CreateWorldScreen *) super;
+        bool is_creative = self->game_mode->text == CREATIVE_STR;
+        std::string description = is_creative ? Strings_creative_mode_description : Strings_survival_mode_description;
+        Screen_drawString(super, super->font, &description, self->game_mode->x, self->game_mode->y + self->game_mode->height + description_padding, 0xa0a0a0);
+    };
+    // Positioning
+    vtable->setupPositions = [](Screen *super) {
+        Screen_setupPositions_non_virtual(super);
+        CreateWorldScreen *self = (CreateWorldScreen *) super;
+        // Height/Width
+        int width = 120;
+        int height = 24;
+        self->create->width = self->back->width = self->game_mode->width = width;
+        int seed_width = self->game_mode->width;
+        int name_width = width * 1.5f;
+        self->create->height = self->back->height = self->game_mode->height = height;
+        int text_box_height = self->game_mode->height;
+        // Find Center Y
+        int top = (title_padding * 2) + line_height;
+        int bottom = super->height - self->create->height - (bottom_padding * 2);
+        int center_y = ((bottom - top) / 2) + top;
+        center_y -= (description_padding + line_height) / 2;
+        // X/Y
+        self->create->y = self->back->y = super->height - bottom_padding - height;
+        self->create->x = self->game_mode->x = (super->width / 2) - inner_padding - width;
+        self->back->x = (super->width / 2) + inner_padding;
+        int seed_x = self->back->x;
+        int name_x = (super->width / 2) - (name_width / 2);
+        int name_y = center_y - inner_padding - height;
+        self->game_mode->y = center_y + inner_padding;
+        int seed_y = self->game_mode->y;
+        // Update Text Boxes
+        self->name->setSize(name_x, name_y, name_width, text_box_height);
+        self->seed->setSize(seed_x, seed_y, seed_width, text_box_height);
+    };
+    // ESC
+    vtable->handleBackEvent = [](Screen *super, bool do_nothing) {
+        if (!do_nothing) {
+            ScreenChooser_setScreen(&super->minecraft->screen_chooser, 5);
         }
+        return true;
+    };
+    // Button Click
+    vtable->buttonClicked = [](Screen *super, Button *button) {
+        CreateWorldScreen *self = (CreateWorldScreen *) super;
+        bool is_creative = self->game_mode->text == CREATIVE_STR;
+        if (button == self->game_mode) {
+            // Toggle Game Mode
+            self->game_mode->text = is_creative ? SURVIVAL_STR : CREATIVE_STR;
+        } else if (button == self->back) {
+            // Back
+            super->vtable->handleBackEvent(super, false);
+        } else if (button == self->create) {
+            // Create
+            create_world(super->minecraft, self->name->getText(), is_creative, self->seed->getText());
+        }
+    };
+}
+static Screen *create_create_world_screen() {
+    // Construct
+    CreateWorldScreen *screen = new CreateWorldScreen;
+    ALLOC_CHECK(screen);
+    Screen_constructor(&screen->super.super);
 
-        // Update State
-        pthread_mutex_lock(&create_world_state_lock);
-        reset_create_world_state();
-        create_world_state.dialog_state = DIALOG_SUCCESS;
-        char *safe_name = to_cp437(world_name);
-        create_world_state.name = safe_name;
-        free(world_name);
-        create_world_state.game_mode = game_mode;
-        create_world_state.seed = seed;
-        pthread_mutex_unlock(&create_world_state_lock);
-        // Return
-        return NULL;
-    }
+    // Set VTable
+    screen->super.super.vtable = get_create_world_screen_vtable();
 
- fail:
-    // Update State
-    pthread_mutex_lock(&create_world_state_lock);
-    reset_create_world_state();
-    pthread_mutex_unlock(&create_world_state_lock);
-    free(world_name);
     // Return
-    return NULL;
+    return (Screen *) screen;
 }
 
-// Create Chat Thead
-static void open_create_world() {
-    // Update State (Assume Lock)
-    create_world_state.dialog_state = DIALOG_OPEN;
-    // Start Thread
-    pthread_t thread;
-    pthread_create(&thread, NULL, create_world_thread, NULL);
+// Unique Level Name (https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/client/gui/screens/CreateWorldScreen.cpp#L65-L83)
+static std::string getUniqueLevelName(LevelStorageSource *source, const std::string &in) {
+    std::set<std::string> maps;
+    std::vector<LevelSummary> vls;
+    source->vtable->getLevelList(source, &vls);
+    for (int i = 0; i < int(vls.size()); i++) {
+        const LevelSummary &ls = vls[i];
+        maps.insert(ls.folder);
+    }
+    std::string out = in;
+    while (maps.find(out) != maps.end()) {
+        out += "-";
+    }
+    return out;
 }
 
 // Create World
-static void create_world(Screen *host_screen, std::string folder_name) {
-    // Get Minecraft
-    Minecraft *minecraft = host_screen->minecraft;
+static void create_world(Minecraft *minecraft, std::string name, bool is_creative, std::string seed_str) {
+    // Get Seed
+    int seed;
+    seed_str = Util_stringTrim(&seed_str);
+    if (!seed_str.empty()) {
+        int num;
+        if (sscanf(seed_str.c_str(), "%d", &num) > 0) {
+            seed = num;
+        } else {
+            seed = Util_hashCode(&seed_str);
+        }
+    } else {
+        seed = Common_getEpochTimeS();
+    }
+
+    // Get Folder Name
+    name = Util_stringTrim(&name);
+    std::string folder = "";
+    for (char c : name) {
+        if (
+            c >= ' ' && c <= '~' &&
+            c != '/' &&
+            c != '\\' &&
+            c != '`' &&
+            c != '?' &&
+            c != '*' &&
+            c != '<' &&
+            c != '>' &&
+            c != '|' &&
+            c != '"' &&
+            c != ':'
+        ) {
+            folder += c;
+        }
+    }
+    if (folder.empty()) {
+        folder = "World";
+    }
+    folder = getUniqueLevelName(Minecraft_getLevelSource(minecraft), folder);
 
     // Settings
     LevelSettings settings;
-    settings.game_type = create_world_state.game_mode;
-    settings.seed = create_world_state.seed;
+    settings.game_type = is_creative;
+    settings.seed = seed;
 
     // Create World
-    std::string world_name = (char *) create_world_state.name;
-    minecraft->vtable->selectLevel(minecraft, &folder_name, &world_name, &settings);
+    minecraft->vtable->selectLevel(minecraft, &folder, &name, &settings);
 
     // Multiplayer
     Minecraft_hostMultiplayer(minecraft, 19132);
@@ -237,55 +230,20 @@ static void create_world(Screen *host_screen, std::string folder_name) {
     ALLOC_CHECK(screen);
     screen = ProgressScreen_constructor(screen);
     Minecraft_setScreen(minecraft, (Screen *) screen);
-
-    // Reset
-    reset_create_world_state();
 }
 
 // Redirect Create World Button
 #define create_SelectWorldScreen_tick_injection(prefix) \
     static void prefix##SelectWorldScreen_tick_injection(prefix##SelectWorldScreen *screen) { \
-        /* Lock */ \
-        pthread_mutex_lock(&create_world_state_lock); \
-        \
-        bool *should_create_world = &screen->should_create_world; \
-        if (*should_create_world) { \
-            /* Check State */ \
-            if (create_world_state.dialog_state == DIALOG_CLOSED) { \
-                /* Open Dialog */ \
-                open_create_world(); \
-            } \
-            \
+        if (screen->should_create_world) { \
+            /* Open Screen */ \
+            Minecraft_setScreen(screen->minecraft, create_create_world_screen()); \
             /* Finish */ \
-            *should_create_world = false; \
+            screen->should_create_world = false; \
         } else { \
             /* Call Original Method */ \
             prefix##SelectWorldScreen_tick_non_virtual(screen); \
         } \
-        \
-        /* Create World If Dialog Succeeded */ \
-        if (create_world_state.dialog_state == DIALOG_SUCCESS) { \
-            /* Create World Dialog Finished */ \
-            \
-            /* Get New World Name */ \
-            std::string name = (char *) create_world_state.name; \
-            std::string new_name = prefix##SelectWorldScreen_getUniqueLevelName(screen, &name); \
-            \
-            /* Create World */ \
-            create_world((Screen *) screen, new_name); \
-        } \
-        \
-        /* Lock/Unlock UI */ \
-        if (create_world_state.dialog_state != DIALOG_OPEN) { \
-            /* Dialog Closed, Unlock UI */ \
-            media_set_interactable(1); \
-        } else { \
-            /* Dialog Open, Lock UI */ \
-            media_set_interactable(0); \
-        } \
-        \
-        /* Unlock */ \
-        pthread_mutex_unlock(&create_world_state_lock); \
     }
 create_SelectWorldScreen_tick_injection()
 create_SelectWorldScreen_tick_injection(Touch_)
diff --git a/mods/src/input/misc.c b/mods/src/input/misc.c
index 1dc74f6c95..ac0a57a9a2 100644
--- a/mods/src/input/misc.c
+++ b/mods/src/input/misc.c
@@ -35,7 +35,7 @@ static void _handle_back(Minecraft *minecraft) {
 }
 
 // Fix OptionsScreen Ignoring The Back Button
-static int32_t OptionsScreen_handleBackEvent_injection(OptionsScreen *screen, bool do_nothing) {
+static bool OptionsScreen_handleBackEvent_injection(OptionsScreen *screen, bool do_nothing) {
     if (!do_nothing) {
         Minecraft *minecraft = screen->minecraft;
         Minecraft_setScreen(minecraft, NULL);
diff --git a/mods/src/text-input-box/TextInputBox.cpp b/mods/src/text-input-box/TextInputBox.cpp
index e91ede1b31..22d0c8e836 100644
--- a/mods/src/text-input-box/TextInputBox.cpp
+++ b/mods/src/text-input-box/TextInputBox.cpp
@@ -2,13 +2,12 @@
 
 #include <mods/text-input-box/TextInputBox.h>
 
-TextInputBox *TextInputBox::create(int id, const std::string &placeholder, const std::string &text) {
+TextInputBox *TextInputBox::create(const std::string &placeholder, const std::string &text) {
     // Construct
     TextInputBox *self = new TextInputBox;
     GuiComponent_constructor(&self->super);
 
     // Setup
-    self->m_ID = id;
     self->m_xPos = 0;
     self->m_yPos = 0;
     self->m_width = 0;
@@ -22,6 +21,7 @@ TextInputBox *TextInputBox::create(int id, const std::string &placeholder, const
     self->m_lastFlashed = 0;
     self->m_pFont = nullptr;
     self->m_maxLength = -1;
+    self->m_scrollPos = 0;
 
     // Return
     return self;
@@ -32,6 +32,7 @@ void TextInputBox::setSize(int x, int y, int width, int height) {
     m_yPos = y;
     m_width = width;
     m_height = height;
+    recalculateScroll();
 }
 
 void TextInputBox::init(Font *pFont) {
@@ -61,6 +62,7 @@ void TextInputBox::keyPressed(int key) {
             }
             m_text.erase(m_text.begin() + m_insertHead - 1, m_text.begin() + m_insertHead);
             m_insertHead--;
+            recalculateScroll();
             break;
         }
         case 0x2e: {
@@ -83,6 +85,7 @@ void TextInputBox::keyPressed(int key) {
             if (m_insertHead < 0) {
                 m_insertHead = 0;
             }
+            recalculateScroll();
             break;
         }
         case 0x27: {
@@ -95,6 +98,7 @@ void TextInputBox::keyPressed(int key) {
             } else {
                 m_insertHead = 0;
             }
+            recalculateScroll();
             break;
         }
         case 0x0d: {
@@ -130,6 +134,7 @@ void TextInputBox::setFocused(bool b) {
         m_lastFlashed = Common_getTimeMs();
         m_bCursorOn = true;
         m_insertHead = int(m_text.size());
+        recalculateScroll();
     }
 }
 
@@ -143,38 +148,64 @@ void TextInputBox::charPressed(int k) {
         return;
     }
 
-    // note: the width will increase by the same amount no matter where K is appended
-    std::string test_str = m_text + char(k);
-    if (m_maxLength != -1 && int(test_str.length()) > m_maxLength) {
+    // Ignore Newlines
+    if (k == '\n') {
         return;
     }
-    int width = Font_width(m_pFont, &test_str);
-    if (width < (m_width - PADDING)) {
-        m_text.insert(m_text.begin() + m_insertHead, k);
-        m_insertHead++;
+
+    // Check Max Length
+    if (m_maxLength != -1 && int(m_text.length()) >= m_maxLength) {
+        return;
     }
+
+    // Insert
+    m_text.insert(m_text.begin() + m_insertHead, k);
+    m_insertHead++;
+    recalculateScroll();
 }
 
+static std::string get_rendered_text(Font *font, int width, int scroll_pos, std::string text) {
+    std::string rendered_text = text.substr(scroll_pos);
+    int max_width = width - (PADDING * 2);
+    while (Font_width(font, &rendered_text) > max_width) {
+        rendered_text.pop_back();
+    }
+    return rendered_text;
+}
+
+static char CURSOR_CHAR = '_';
+
 void TextInputBox::render() {
     GuiComponent_fill(&super, m_xPos, m_yPos, m_xPos + m_width, m_yPos + m_height, 0xFFAAAAAA);
     GuiComponent_fill(&super, m_xPos + 1, m_yPos + 1, m_xPos + m_width - 1, m_yPos + m_height - 1, 0xFF000000);
 
-    int textYPos = (m_height - 8) / 2;
-
+    int text_color;
+    int scroll_pos;
+    std::string rendered_text;
     if (m_text.empty()) {
-        GuiComponent_drawString(&super, m_pFont, &m_placeholder, m_xPos + PADDING, m_yPos + textYPos, 0x404040);
+        rendered_text = m_placeholder;
+        text_color = 0x404040;
+        scroll_pos = 0;
     } else {
-        GuiComponent_drawString(&super, m_pFont, &m_text, m_xPos + PADDING, m_yPos + textYPos, 0xFFFFFF);
+        rendered_text = m_text;
+        text_color = 0xffffff;
+        scroll_pos = m_scrollPos;
     }
+    rendered_text = get_rendered_text(m_pFont, m_width, scroll_pos, rendered_text);
+
+    int textYPos = (m_height - 8) / 2;
+    GuiComponent_drawString(&super, m_pFont, &rendered_text, m_xPos + PADDING, m_yPos + textYPos, text_color);
 
     if (m_bCursorOn) {
-        int xPos = 5;
+        int cursor_pos = m_insertHead - m_scrollPos;
+        if (cursor_pos >= 0 && cursor_pos <= int(rendered_text.length())) {
+            std::string substr = rendered_text.substr(0, cursor_pos);
+            int xPos = PADDING + Font_width(m_pFont, &substr);
 
-        std::string substr = m_text.substr(0, m_insertHead);
-        xPos += Font_width(m_pFont, &substr);
-
-        std::string str = "_";
-        GuiComponent_drawString(&super, m_pFont, &str, m_xPos + xPos, m_yPos + textYPos + 2, 0xFFFFFF);
+            std::string str;
+            str += CURSOR_CHAR;
+            GuiComponent_drawString(&super, m_pFont, &str, m_xPos + xPos, m_yPos + textYPos + 2, 0xffffff);
+        }
     }
 }
 
@@ -198,3 +229,66 @@ bool TextInputBox::clicked(int xPos, int yPos) {
 
     return true;
 }
+
+void TextInputBox::recalculateScroll() {
+    // Skip If Size Unset
+    if (m_width == 0) {
+        return;
+    }
+    // Ensure Cursor Is Visible
+    bool is_cursor_at_end = m_insertHead == int(m_text.length());
+    if (m_scrollPos >= m_insertHead && m_scrollPos > 0) {
+        // Cursor Is At Scroll Position
+        // Move Back Scroll As Far As Possible
+        while (true) {
+            int test_scroll_pos = m_scrollPos - 1;
+            std::string rendered_text = m_text;
+            if (is_cursor_at_end) {
+                rendered_text += CURSOR_CHAR;
+            }
+            rendered_text = get_rendered_text(m_pFont, m_width, test_scroll_pos, rendered_text);
+            int cursor_pos = m_insertHead - test_scroll_pos;
+            if (cursor_pos >= int(rendered_text.length())) {
+                break;
+            } else {
+                m_scrollPos = test_scroll_pos;
+                if (m_scrollPos == 0) {
+                    break;
+                }
+            }
+        }
+    } else {
+        // Cursor After Scroll Area
+        // Increase Scroll So Cursor Is Visible
+        while (true) {
+            std::string rendered_text = m_text;
+            if (is_cursor_at_end) {
+                rendered_text += CURSOR_CHAR;
+            }
+            rendered_text = get_rendered_text(m_pFont, m_width, m_scrollPos, rendered_text);
+            int cursor_pos = m_insertHead - m_scrollPos;
+            if (cursor_pos < int(rendered_text.length())) {
+                break;
+            } else {
+                if (m_scrollPos == int(m_text.length())) {
+                    WARN("Text Box Is Too Small");
+                    break;
+                } else {
+                    m_scrollPos++;
+                }
+            }
+        }
+    }
+}
+
+std::string TextInputBox::getText() {
+    return m_text;
+}
+
+bool TextInputBox::isFocused() {
+    return m_bFocused;
+}
+
+void TextInputBox::setMaxLength(int max_length) {
+    m_maxLength = max_length;
+}
diff --git a/mods/src/touch/touch.cpp b/mods/src/touch/touch.cpp
index 67d20f9215..dd4de2eaf4 100644
--- a/mods/src/touch/touch.cpp
+++ b/mods/src/touch/touch.cpp
@@ -2,6 +2,7 @@
 
 #include <mods/feature/feature.h>
 #include <mods/init/init.h>
+#include <mods/touch/touch.h>
 
 #include <symbols/minecraft.h>
 
@@ -40,9 +41,27 @@ static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(Gu
     GuiComponent_drawCenteredString(component, font, text, x, y, color);
 }
 
+// Create Button
+static int touch_gui = 0;
+Button *touch_create_button(int id, std::string text) {
+    Button *button = nullptr;
+    if (touch_gui) {
+        button = (Button *) new Touch_TButton;
+    } else {
+        button = new Button;
+    }
+    ALLOC_CHECK(button);
+    if (touch_gui) {
+        Touch_TButton_constructor((Touch_TButton *) button, id, &text);
+    } else {
+        Button_constructor(button, id, &text);
+    }
+    return button;
+}
+
 // Init
 void init_touch() {
-    int touch_gui = feature_has("Full Touch GUI", server_disabled);
+    touch_gui = feature_has("Full Touch GUI", server_disabled);
     int touch_buttons = touch_gui;
     if (touch_gui) {
         // Main UI
diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt
index eb06b629df..7cd1b13065 100644
--- a/symbols/CMakeLists.txt
+++ b/symbols/CMakeLists.txt
@@ -76,6 +76,7 @@ set(SRC
     src/level/ServerLevel.def
     src/level/Dimension.def
     src/level/MultiPlayerLevel.def
+    src/level/LevelSummary.def
     src/item/ItemRenderer.def
     src/item/ItemInHandRenderer.def
     src/item/AuxDataTileItem.def
@@ -100,6 +101,7 @@ set(SRC
     src/gui/screens/StartMenuScreen.def
     src/gui/screens/ProgressScreen.def
     src/gui/screens/Touch_SelectWorldScreen.def
+    src/gui/screens/ScreenChooser.def
     src/gui/Font.def
     src/gui/components/ImageButton.def
     src/gui/components/OptionButton.def
@@ -142,6 +144,7 @@ set(SRC
     src/misc/Config.def
     src/misc/Random.def
     src/misc/Mth.def
+    src/misc/Util.def
     src/input/IMoveInput.def
     src/input/IBuildInput.def
     src/input/MouseBuildInput.def
diff --git a/symbols/src/game/Minecraft.def b/symbols/src/game/Minecraft.def
index 637a92f711..04707c03e3 100644
--- a/symbols/src/game/Minecraft.def
+++ b/symbols/src/game/Minecraft.def
@@ -41,6 +41,7 @@ property int progress = 0xc60;
 property PerfRenderer *perf_renderer = 0xcbc;
 property CommandServer *command_server = 0xcc0;
 property Font *font = 0x16c;
+property ScreenChooser screen_chooser = 0x168;
 
 // Smooth Lighting
 static-property bool useAmbientOcclusion = 0x136b90;
diff --git a/symbols/src/gui/components/Button.def b/symbols/src/gui/components/Button.def
index cf2bb7ba6b..1b3d078b62 100644
--- a/symbols/src/gui/components/Button.def
+++ b/symbols/src/gui/components/Button.def
@@ -9,3 +9,4 @@ property int width = 0x14;
 property int height = 0x18;
 property int x = 0xc;
 property int y = 0x10;
+property std::string text = 0x1c;
diff --git a/symbols/src/gui/screens/Screen.def b/symbols/src/gui/screens/Screen.def
index 79c3818716..fe904fca08 100644
--- a/symbols/src/gui/screens/Screen.def
+++ b/symbols/src/gui/screens/Screen.def
@@ -10,7 +10,7 @@ virtual-method void updateEvents() = 0x14;
 virtual-method void keyboardNewChar(char key) = 0x70;
 virtual-method void keyPressed(int key) = 0x6c;
 virtual-method void render(int x, int y, float param_1) = 0x8;
-virtual-method bool handleBackEvent(bool param_1)  = 0x24;
+virtual-method bool handleBackEvent(bool do_nothing)  = 0x24;
 virtual-method void tick() = 0x28;
 virtual-method void buttonClicked(Button *button) = 0x60;
 virtual-method void init() = 0xc;
diff --git a/symbols/src/gui/screens/ScreenChooser.def b/symbols/src/gui/screens/ScreenChooser.def
new file mode 100644
index 0000000000..bb2984b214
--- /dev/null
+++ b/symbols/src/gui/screens/ScreenChooser.def
@@ -0,0 +1 @@
+method void setScreen(uint id) = 0x29490;
diff --git a/symbols/src/level/LevelStorageSource.def b/symbols/src/level/LevelStorageSource.def
index 58e62e69fc..723f01becb 100644
--- a/symbols/src/level/LevelStorageSource.def
+++ b/symbols/src/level/LevelStorageSource.def
@@ -1 +1,2 @@
 virtual-method void deleteLevel(std::string *level_name) = 0x20;
+virtual-method void getLevelList(std::vector<LevelSummary> *level_list) = 0xc;
diff --git a/symbols/src/level/LevelSummary.def b/symbols/src/level/LevelSummary.def
new file mode 100644
index 0000000000..fc82426922
--- /dev/null
+++ b/symbols/src/level/LevelSummary.def
@@ -0,0 +1,7 @@
+size 0x14;
+
+property std::string folder = 0x0;
+property std::string name = 0x4;
+property int seed = 0x8;
+property int game_mode = 0xc;
+property int param_5 = 0x10;
diff --git a/symbols/src/misc/Common.def b/symbols/src/misc/Common.def
index 1d75668f95..de81022c9d 100644
--- a/symbols/src/misc/Common.def
+++ b/symbols/src/misc/Common.def
@@ -6,3 +6,4 @@ static-method void sleepMs(int x) = 0x13cf4;
 static-method int sdl_key_to_minecraft_key(int sdl_key) = 0x1243c;
 static-method void anGenBuffers(int count, uint *buffers) = 0x5f28c;
 static-method int getTimeMs() = 0x13cd4;
+static-method int getEpochTimeS() = 0x13d00;
diff --git a/symbols/src/misc/PerfRenderer.def b/symbols/src/misc/PerfRenderer.def
index eea41e6aa4..9af6b065ee 100644
--- a/symbols/src/misc/PerfRenderer.def
+++ b/symbols/src/misc/PerfRenderer.def
@@ -1 +1,2 @@
-method void debugFpsMeterKeyPress(int key) = 0x79118;
\ No newline at end of file
+method void debugFpsMeterKeyPress(int key) = 0x79118;
+method void renderFpsMeter(float param_1) = 0x79280;
diff --git a/symbols/src/misc/Strings.def b/symbols/src/misc/Strings.def
index f83046fcf9..10898c00e3 100644
--- a/symbols/src/misc/Strings.def
+++ b/symbols/src/misc/Strings.def
@@ -7,4 +7,6 @@ static-property char *options_txt_fopen_mode_when_loading = 0x19d24; // w
 static-property char **feedback_vibration_options_txt_name_1 = 0x198a0; // feedback_vibration
 static-property char **feedback_vibration_options_txt_name_2 = 0x194bc; // feedback_vibration
 static-property char **gfx_lowquality_options_txt_name = 0x194c4; // gfx_lowquality
-static-property char *classic_create_button_text = 0x39bec; // Create
\ No newline at end of file
+static-property char *classic_create_button_text = 0x39bec; // Create
+static-property-array char creative_mode_description = 0x104492; // Unlimited resources and flying
+static-property-array char survival_mode_description = 0x104470; // Mobs, health and gather resources
diff --git a/symbols/src/misc/Util.def b/symbols/src/misc/Util.def
new file mode 100644
index 0000000000..4e6c6d4902
--- /dev/null
+++ b/symbols/src/misc/Util.def
@@ -0,0 +1,3 @@
+static-method std::string stringTrim(std::string *str) = 0x77c40;
+static-method int hashCode(std::string *str) = 0x77a50;
+static-method std::string *stringReplace(std::string *str, std::string *what, std::string *with, int param_1) = 0x779f0;
diff --git a/symbols/src/network/packet/ChatPacket.def b/symbols/src/network/packet/ChatPacket.def
index aed55cc765..35b8833dd5 100644
--- a/symbols/src/network/packet/ChatPacket.def
+++ b/symbols/src/network/packet/ChatPacket.def
@@ -1,3 +1,5 @@
 extends Packet;
 
+vtable 0x108a98;
+
 property char *message = 0xc;