From db7a5f9519b85d299496a3c89d3030cb8978120e Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 22:29:32 -0500 Subject: [PATCH 01/29] feat: restore unused java GUI Co-Authored-By: ffqq <36998498+realffqq@users.noreply.github.com> --- 4J.Input/4J_Input.cpp | 8 ++ 4J.Input/4J_Input.h | 3 + Minecraft.Assets/Common/res/gui/furnace.png | Bin 3153 -> 1520 bytes Minecraft.Client/Minecraft.cpp | 96 +++++++++------ .../Platform/Common/UI/UIController.cpp | 4 + .../Platform/Common/UI/UIScene_MainMenu.cpp | 2 + Minecraft.Client/Player/LocalPlayer.cpp | 35 ++++-- .../EntityRenderers/ItemRenderer.cpp | 1 + Minecraft.Client/Rendering/GameRenderer.cpp | 11 +- Minecraft.Client/Textures/Textures.cpp | 16 ++- Minecraft.Client/Textures/Textures.h | 16 ++- Minecraft.Client/UI/Gui.cpp | 10 +- Minecraft.Client/UI/Screen.cpp | 59 ++++++++- .../UI/Screens/AbstractContainerScreen.cpp | 31 ++--- .../UI/Screens/AchievementPopup.cpp | 18 +-- .../UI/Screens/ContainerScreen.cpp | 4 +- .../UI/Screens/CraftingScreen.cpp | 4 +- .../UI/Screens/CreateWorldScreen.cpp | 113 +++++++++++++++++- .../UI/Screens/CreateWorldScreen.h | 32 +++++ Minecraft.Client/UI/Screens/FurnaceScreen.cpp | 4 +- .../UI/Screens/InventoryScreen.cpp | 4 +- Minecraft.Client/UI/Screens/PauseScreen.cpp | 27 +++-- Minecraft.Client/UI/Screens/PauseScreen.h | 2 +- Minecraft.Client/UI/Screens/TitleScreen.cpp | 35 +++++- meson.build | 4 + meson.options | 4 + 26 files changed, 440 insertions(+), 103 deletions(-) create mode 100644 meson.options diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index b0946a810..8f6f880a8 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -534,3 +534,11 @@ bool C_4JInput::VerifyStrings(WCHAR ** /*pwStringA*/, int /*iStringC*/, int(*/*Func*/)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID /*lpParam*/) { return true; } void C_4JInput::CancelQueuedVerifyStrings(int(*/*Func*/)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID /*lpParam*/) {} void C_4JInput::CancelAllVerifyInProgress(void) {} + +float C_4JInput::GetMouseX() { + return (float)s_lastCursorX; +} + +float C_4JInput::GetMouseY() { + return (float)s_lastCursorY; +} \ No newline at end of file diff --git a/4J.Input/4J_Input.h b/4J.Input/4J_Input.h index 9ac5c55d1..b0120927b 100644 --- a/4J.Input/4J_Input.h +++ b/4J.Input/4J_Input.h @@ -131,6 +131,9 @@ public: void CancelAllVerifyInProgress(void); //bool InputDetected(DWORD dwUserIndex,WCHAR *pwchInput); + + float GetMouseX(); + float GetMouseY(); }; // Singleton diff --git a/Minecraft.Assets/Common/res/gui/furnace.png b/Minecraft.Assets/Common/res/gui/furnace.png index a5834e19516d760d1dc1b87db3e8abee756d9884..8527289e56457be68d73bab99d4906760defcbed 100644 GIT binary patch literal 1520 zcmcIkc~Fx_6n|g*5Qr5LOa+ky3d(xM^ zaVg#y4**NOJU#pX5X}++oyD4I+rh#;3n`W=v`YFNcEZUG0moSjF&f4`<^aE{}W2@aZ57*Exwn>7o7OJWBqitMSzj^L>o~X z+a}_$&MfPtUB(+|5eR1CGbheyeG(H*?lVCXFYdc68 zAGI#sReGd3-qppP6QmpzmzS3teYCjo_b$~-rwu*lA0JYrY3G*pxv_k=2geGHPhlqwLn$Z zJT6sD7kDiLXZgJF`!|C^hot(3&@d{hc2hdYcz^ha!*c41E2W9)QeiOv`73>EZ)hj^2yt_l zCTbntMCAErh1i)v;je+=?rK_Hrf?6_{TZI3R9165@8wcux0>E0oGK}`80xW_seQp1 z$LWA^Xdp}Z^r~xH${|JV^U{!PL6^)5c#f;?MvyW8?c29sblXtcQ_lMl)A{KzdDCzv z)b2QNQQB5^gXy=v&Hx;=QP4qHus8B{euYUpg4O4UKx9Ru(Hs!j^~S@|(Njb5qoboZ zc*;#{JnJ_ZjKk_19l`9ukReF;lS_akT)@6_x`x7U$&QzH;iuKHHy97^Kz~yZ(MwViYV(=`U9*m{i2~g}D3(?@ht!EC{ zlSuB0jNcT{iXRIf_n&(VK*sv_4|VogOOuzRhTw`5_eFO3G-|N`)0P+)P%OaUQD>+F zvQUmCR=g;y1aitWSua*Q|5iN<|Uuud^&2t z^|Ux_a5HR@ieh&KE^m0y&S*-QVw60tK>y}{pW&?v0_1D#5?MgoqTbHt@RiLBj=#Nm z@;O^`^W}Ow_~w$R3r_4=51Bw|N+f=Bjr)4-jl>w}u;G%~HS}9oh8e^b$~*ZVq{lS( zbJ8*c5&9Xig^_N0VrJOGY?vc3vB8ZMF3MVmJmU|gMs<^$Phv0M{#O4@%U`^xh^i56 z*>VzVDw<=|NCSM(<8}wlC06gE*Ibupi`ZH&?2ntMQv8h!9QQR^+)z~26c}fc-Jy9# z|D^c?I&pO*josiOhr1wcKlucyB;wS99w9(ngiU*rs-mz7iFWdI0^lZ3c{YrIy^|8R?n(wg^*(+> zw@<}NG2zk_S5}H|LR89uu%t-f9kwq%#d3$MA0^G&(#F!7KfJ3G0OjZIE>3<2gQf5K zQ!m+R=kyQneOja>>zngb>+tyTT65>av=4duAJoI?lIpFQ%|p}MH6!ld8|0)KFaQ3k zwzX$K&N#4`ZKpUAE$!*)8EE9rHB@k4jeL;04T%hV$KI)b%of*Ns$XQAJvT90o1j^= z%}`z{;2b_II=1FRPzVhlP2Y}>8E%AYGhwZDoT1DQdbtJxP)8pVs8NAQ{A;ZxeR>VPP(^P#6%C6?tX1#L zwz{E2M1j9a9zt7P*RJ14qGZp=X=kUVu7$22oHtG0T#djK06#9W=cy*Ra3Y{RCR6dE z85ZbhRAD}_GRJfjRDmd2*2fP;f=V|UbGrQS1J?a7&LdM2R=bNRyJ$*?2mig~A z$*VZbSE2;Kw+m$-gtPHlSs@ixvr?MhA6`(tjXh*>9r}ebTij{8qd=A}pfHKCt&Uly zBN0_LdgO%3Ge1Xjf-aXKZ)fHWcFa}|Y0ma*)YSlHtuVQ9p^nVcaWR7&PA|l;K27zkw%89w+PY6P zR@!oHJ@s+xJ$`w^p&CH6mAT^`#gP>4dg!`!Ow8ugMGKiKYYD>N<3e zXsX~fCx&%0osF$jHe;*4z3t{?9tvIxovQ-m>@tAmZJC2&Il*d4Ivg|h&%PJc%iy!a z8Nz#uj0Jhx;+@kZ6!-y^QUxEFrMwwhKm9&o*yopE$Yqc8c9+|U0B1K6WoXX?EwowF zE(?^(t0vz}29_WzlqHKH3pw|z6TfGoo%f(E9ORU)*^-EOZwQtOxh$yS%*OWxzSOSn z9FTtD{TX(pP7(`xNgVJRIRl84EvkrjSn0~}q&(a~>Ji)WLIZAGXRiz|GsPF&af}~H z<2Y}07;Ufr7TB}u-&_l=P5DEA^}vNianh+8$B6=|fk-YG_`WZ2q44=Y;145ofaIH@ zcie@HJ`-W3N$?EiS!r|flo!A>irVyeV+=qCOW~s8pUeCSoT$O6uVb;TK9G6Hqc6MB zqupg6dol`J<{4TUcN`Pry$#}QO)@Ovu3?GNpxVuvKn5g=klL;J*rJEMBy>L9n2N8d zgIUF6J=RFK=8tiKFZ5*}gTRN6df)F~gZ5j4J8-wwqng%Z`6@W=_il$RNui!ffms*s ziejO~kkNzX?T;`dLligCm!u#{y?gYSn+~dkf^}=q8b}((!Na4VR~q5N!^tEI%VUE< z_@A}>Z0v-AhCDo0J>KggF9I=zB#(d)~FJr;|tg8Ywa1Ls@jpBF}iNm5|=T!>#U7mh46;YWitJ{!pIu zP+CJzLE6pF+hm?r~p7llvam6Lgw*3qR)sFO+W#PY5@y3|nav9Y$$zLzn$9UzJ4v>|o$8+aedhgmF*k0%}D zW6POPQ*QcOBdm`P$Fzr6x&kDWSZ8!qH)}c59X}cY^tSIB)^jXFJs7{5qOMhU;XT2x ze*B1RjsyN8(UydgMnsI0SShSAHZ-!2qr@#Ttv-MHU*h z&F;5#CWN_C*1+fTrjtGog5RMcg{oi0Ei>5nfP%IdUca-@o&P0~z$jlQqd`3;u5zVv z=2@Gj>)^6PK9_c%zbUJ*u+XEvvDxU|yV6y3knqiGfA|xw3Q_W;$*Xh+-j$Kg*w{&` zKF~V)E}5kvRwGGX>txihi-n&oo==v%I8xy*?iPCmPSW^7NTkA|MR*Fag>>M__{W#~ z8W%+kg{q{fhSA6dAZO(z+|4tz%|9jk-SERYQvL6yGRd{e2bdx)6Ba3bMb89D?%FFJ*=+Uw(&e1dz{yd@==)yFtaYR|DomuH i;Qzz_Xbza9S+xrP#suf+APV;T58PdMxZKzhn)xsIHi#7f diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 80c75bad5..5684c065b 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1,6 +1,7 @@ #include "Platform/stdafx.h" #include "Minecraft.h" #include "GameState/GameMode.h" +#include "UI/Screens/PauseScreen.h" #include "Utils/Timer.h" #include "Rendering/EntityRenderers/ProgressRenderer.h" #include "Rendering/LevelRenderer.h" @@ -423,7 +424,7 @@ void Minecraft::renderLoadingScreen() { // 4J Unused // testing stuff on vita just now -#ifdef __PSVITA__ +#if (defined (__PSVITA__) || defined (ENABLE_JAVA_GUIS)) ScreenSizeCalculator ssc(options, width, height); // xxx @@ -464,7 +465,7 @@ void Minecraft::renderLoadingScreen() glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1f); - Display::swapBuffers(); + // Display::swapBuffers(); // xxx RenderManager.Present(); #endif @@ -557,8 +558,9 @@ void Minecraft::setScreen(Screen *screen) } else if (player != NULL && !ui.GetMenuDisplayed(player->GetXboxPad()) && player->getHealth() <= 0) { - //screen = new DeathScreen(); - +#ifdef ENABLE_JAVA_GUIS + screen = new DeathScreen(); +#else // 4J Stu - If we exit from the death screen then we are saved as being dead. In the Java // game when you load the game you are still dead, but this is silly so only show the dead // screen if we have died during gameplay @@ -570,9 +572,10 @@ void Minecraft::setScreen(Screen *screen) { ui.NavigateToScene(player->GetXboxPad(),eUIScene_DeathMenu,NULL); } +#endif } - if (dynamic_cast(screen)!=NULL) + if (screen != NULL && dynamic_cast(screen)!=NULL) { options->renderDebug = false; gui->clearMessages(); @@ -595,29 +598,22 @@ void Minecraft::setScreen(Screen *screen) // 4J-PB - if a screen has been set, go into menu mode // it's possible that player doesn't exist here yet - /*if(screen!=NULL) +#ifdef ENABLE_JAVA_GUIS + if (screen!=NULL) { - if(player && player->GetXboxPad()!=-1) - { - InputManager.SetMenuDisplayed(player->GetXboxPad(),true); + if (player && player->GetXboxPad()!=-1) + { + InputManager.SetMenuDisplayed(player->GetXboxPad(),true); + } } else { - // set all - //InputManager.SetMenuDisplayed(XUSER_INDEX_ANY,true); + if(player && player->GetXboxPad()!=-1) + { + InputManager.SetMenuDisplayed(player->GetXboxPad(),false); + } } - } - else - { - if(player && player->GetXboxPad()!=-1) - { - InputManager.SetMenuDisplayed(player->GetXboxPad(),false); - } - else - { - //InputManager.SetMenuDisplayed(XUSER_INDEX_ANY,false); - } - }*/ +#endif } void Minecraft::checkGlError(const std::wstring& string) @@ -1434,6 +1430,9 @@ void Minecraft::run_middle() { localplayers[i]->ullButtonsPressed|=1LL<ullButtonsPressed|=1LL<updateEvents(); + } + ui.HandleGameTick(); setLocalPlayerIdx(ProfileManager.GetPrimaryPad()); @@ -1948,8 +1952,11 @@ void Minecraft::run_middle() MemSect(0); frames++; //pause = !isClientSide() && screen != NULL && screen->isPauseScreen(); - //pause = g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad()); +#ifdef ENABLE_JAVA_GUIS + pause = g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && screen != nullptr && screen->isPauseScreen(); +#else pause = app.IsAppPaused(); +#endif #ifndef _CONTENT_PACKAGE while (System::nanoTime() >= lastTime + 1000000000) @@ -2098,9 +2105,14 @@ void Minecraft::stop() void Minecraft::pauseGame() { - if (screen != NULL) return; - - // setScreen(new PauseScreen()); // 4J - TODO put back in + if (screen != NULL) + { + setScreen(NULL); + return; + } +#ifdef ENABLE_JAVA_GUIS + setScreen(new PauseScreen()); // 4J - TODO put back in +#endif } void Minecraft::resize(int width, int height) @@ -2161,7 +2173,9 @@ void Minecraft::levelTickThreadInitFunc() // 4J - added bUpdateTextures, which is true if the actual renderer textures are to be updated - this will be true for the last time this tick runs with bFirst true void Minecraft::tick(bool bFirst, bool bUpdateTextures) { - int iPad=player->GetXboxPad(); + int iPad = -1; + if (player) + iPad = player->GetXboxPad(); //OutputDebugString("Minecraft::tick\n"); //4J-PB - only tick this player's stats @@ -2228,12 +2242,12 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) setScreen(NULL); } - if (screen != NULL) - { - player->missTime = 10000; - player->lastClickTick[0] = ticks + 10000; - player->lastClickTick[1] = ticks + 10000; - } + // if (screen != NULL) + // { + // player->missTime = 10000; + // player->lastClickTick[0] = ticks + 10000; + // player->lastClickTick[1] = ticks + 10000; + // } if (screen != NULL) { @@ -3371,7 +3385,11 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) { std::shared_ptr player = std::dynamic_pointer_cast( Minecraft::GetInstance()->player ); ui.PlayUISFX(eSFX_Press); +#ifdef ENABLE_JAVA_GUIS + setScreen(new InventoryScreen(player)); +#else app.LoadInventoryMenu(iPad,player); +#endif } if((player->ullButtonsPressed&(1LL<isInputAllowed(MINECRAFT_ACTION_CRAFTING)) @@ -3410,7 +3428,9 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) { app.DebugPrintf("PAUSE PRESS PROCESSING - ipad = %d, NavigateToScene\n",player->GetXboxPad()); ui.PlayUISFX(eSFX_Press); +#ifndef ENABLE_JAVA_GUIS ui.NavigateToScene(iPad, eUIScene_PauseMenu, NULL, eUILayer_Scene); +#endif } if((player->ullButtonsPressed&(1LL<isInputAllowed(MINECRAFT_ACTION_DROP)) @@ -3455,10 +3475,10 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) else { // 4J-PB - if (InputManager.GetValue(iPad, ACTION_MENU_CANCEL) > 0 && gameMode->isInputAllowed(ACTION_MENU_CANCEL)) - { - setScreen(NULL); - } + // if (InputManager.GetValue(iPad, ACTION_MENU_CANCEL) > 0 && gameMode->isInputAllowed(ACTION_MENU_CANCEL)) + // { + // setScreen(NULL); + // } } // monitor for keyboard input diff --git a/Minecraft.Client/Platform/Common/UI/UIController.cpp b/Minecraft.Client/Platform/Common/UI/UIController.cpp index e697b6369..3a7811ff7 100644 --- a/Minecraft.Client/Platform/Common/UI/UIController.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIController.cpp @@ -10,6 +10,7 @@ #include "../../Minecraft.World/Headers/net.minecraft.world.entity.boss.enderdragon.h" #include "../../Minecraft.Client/Rendering/EntityRenderers/EnderDragonRenderer.h" #include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h" +#include "../../Minecraft.Client/UI/Screens/TitleScreen.h" #include "UIFontData.h" #ifdef __PSVITA__ #include @@ -1585,6 +1586,9 @@ void UIController::NavigateToHomeMenu() else { ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MainMenu); +#ifdef ENABLE_JAVA_GUIS + pMinecraft->setScreen(new TitleScreen()); +#endif } } diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp index 207dc28a5..1a2d9fe11 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp @@ -1809,8 +1809,10 @@ void UIScene_MainMenu::tick() if(s_mainMenuTickCount % 60 == 1) { fprintf(stderr, "[MM] tick %d\n", s_mainMenuTickCount); fflush(stderr); } if(s_mainMenuTickCount == 90) // ~3 seconds at 30fps { +#ifndef ENABLE_JAVA_GUIS fprintf(stderr, "[Linux] Auto-starting trial world from MainMenu after %d ticks\n", s_mainMenuTickCount); LoadTrial(); +#endif return; } } diff --git a/Minecraft.Client/Player/LocalPlayer.cpp b/Minecraft.Client/Player/LocalPlayer.cpp index dee185522..673014470 100644 --- a/Minecraft.Client/Player/LocalPlayer.cpp +++ b/Minecraft.Client/Player/LocalPlayer.cpp @@ -585,25 +585,37 @@ void LocalPlayer::closeContainer() void LocalPlayer::openTextEdit(std::shared_ptr sign) { +#ifdef ENABLE_JAVA_GUIS + minecraft->setScreen(new TextEditScreen(sign)); + bool success = true; +#else bool success = app.LoadSignEntryMenu(GetXboxPad(), sign ); if( success ) ui.PlayUISFX(eSFX_Press); - //minecraft->setScreen(new TextEditScreen(sign)); +#endif } bool LocalPlayer::openContainer(std::shared_ptr container) { +#ifdef ENABLE_JAVA_GUIS + minecraft->setScreen(new ContainerScreen(inventory, container)); + bool success = true; +#else bool success = app.LoadContainerMenu(GetXboxPad(), inventory, container ); if( success ) ui.PlayUISFX(eSFX_Press); - //minecraft->setScreen(new ContainerScreen(inventory, container)); +#endif return success; } bool LocalPlayer::startCrafting(int x, int y, int z) { +#ifdef ENABLE_JAVA_GUIS + minecraft->setScreen(new CraftingScreen(inventory, level, x, y, z)); + bool success = true; +#else bool success = app.LoadCrafting3x3Menu(GetXboxPad(), std::dynamic_pointer_cast( shared_from_this() ), x, y, z ); if( success ) ui.PlayUISFX(eSFX_Press); +#endif //app.LoadXuiCraftMenu(0,inventory, level, x, y, z); - //minecraft->setScreen(new CraftingScreen(inventory, level, x, y, z)); return success; } @@ -617,17 +629,26 @@ bool LocalPlayer::startEnchanting(int x, int y, int z) bool LocalPlayer::startRepairing(int x, int y, int z) { +#ifdef ENABLE_JAVA_GUIS + // minecraft.setScreen(new RepairScreen(inventory, level, x, y, z)); + // FUCK YOU 4J FIRST AND FOREMOST + bool success = true; +#else bool success = app.LoadRepairingMenu(GetXboxPad(), inventory, level, x, y, z ); if( success ) ui.PlayUISFX(eSFX_Press); - //minecraft.setScreen(new RepairScreen(inventory, level, x, y, z)); +#endif return success; } bool LocalPlayer::openFurnace(std::shared_ptr furnace) { +#ifdef ENABLE_JAVA_GUIS + minecraft->setScreen(new FurnaceScreen(inventory, furnace)); + bool success = true; +#else bool success = app.LoadFurnaceMenu(GetXboxPad(),inventory, furnace); if( success ) ui.PlayUISFX(eSFX_Press); - //minecraft->setScreen(new FurnaceScreen(inventory, furnace)); +#endif return success; } @@ -759,10 +780,10 @@ void LocalPlayer::awardStat(Stat *stat, byteArray param) Achievement *ach = (Achievement *) stat; // 4J-PB - changed to attempt to award everytime - the award may need a storage device, so needs a primary player, and the player may not have been a primary player when they first 'got' the award // so let the award manager figure it out - //if (!minecraft->stats[m_iPad]->hasTaken(ach)) + if (!minecraft->stats[m_iPad]->hasTaken(ach)) { // 4J-PB - Don't display the java popup - //minecraft->achievementPopup->popup(ach); + minecraft->achievementPopup->popup(ach); // 4J Stu - Added this function in the libraries as some achievements don't get awarded to all players // e.g. Splitscreen players cannot get theme/avatar/gamerpic and Trial players cannot get any diff --git a/Minecraft.Client/Rendering/EntityRenderers/ItemRenderer.cpp b/Minecraft.Client/Rendering/EntityRenderers/ItemRenderer.cpp index 6e3ecce1d..b93ac4d4a 100644 --- a/Minecraft.Client/Rendering/EntityRenderers/ItemRenderer.cpp +++ b/Minecraft.Client/Rendering/EntityRenderers/ItemRenderer.cpp @@ -327,6 +327,7 @@ extern IDirect3DDevice9 *g_pD3DDevice; // 4J - this used to take x and y as ints, and no scale and alpha - but this interface is now implemented as a wrapper round this more fully featured one void ItemRenderer::renderGuiItem(Font *font, Textures *textures, std::shared_ptr item, float x, float y, float fScaleX,float fScaleY, float fAlpha, bool useCompiled) { + if (!item) return; int itemId = item->id; int itemAuxValue = item->getAuxValue(); Icon *itemIcon = item->getIcon(); diff --git a/Minecraft.Client/Rendering/GameRenderer.cpp b/Minecraft.Client/Rendering/GameRenderer.cpp index 3a135655b..f8fd858fd 100644 --- a/Minecraft.Client/Rendering/GameRenderer.cpp +++ b/Minecraft.Client/Rendering/GameRenderer.cpp @@ -1,6 +1,7 @@ #include "../Platform/stdafx.h" #include "GameRenderer.h" #include "EntityRenderers/ItemInHandRenderer.h" +#include "Input/Input.h" #include "LevelRenderer.h" #include "Frustum.h" #include "FrustumCuller.h" @@ -1071,8 +1072,8 @@ void GameRenderer::render(float a, bool bFirst) ScreenSizeCalculator ssc(mc->options, mc->width, mc->height); int screenWidth = ssc.getWidth(); int screenHeight = ssc.getHeight(); - int xMouse = Mouse::getX() * screenWidth / fbw; - int yMouse = screenHeight - Mouse::getY() * screenHeight / fbh - 1; + int xMouse = InputManager.GetMouseX() * screenWidth / fbw; + int yMouse = InputManager.GetMouseY() * screenHeight / fbh - 1; int maxFps = 0;//getFpsCap(mc->options->framerateLimit); @@ -1116,8 +1117,14 @@ void GameRenderer::render(float a, bool bFirst) if (mc->screen != NULL) { glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.01f); mc->screen->render(xMouse, yMouse, a); if (mc->screen != NULL && mc->screen->particles != NULL) mc->screen->particles->render(a); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); } } diff --git a/Minecraft.Client/Textures/Textures.cpp b/Minecraft.Client/Textures/Textures.cpp index 0974a3f66..3e380cbbb 100644 --- a/Minecraft.Client/Textures/Textures.cpp +++ b/Minecraft.Client/Textures/Textures.cpp @@ -29,14 +29,26 @@ int Textures::preLoadedIdx[TN_COUNT]; const wchar_t *Textures::preLoaded[TN_COUNT] = { L"%blur%misc/pumpkinblur", -// L"%blur%/misc/vignette", // Not currently used +#ifdef ENABLE_JAVA_GUIS + L"%blur%/misc/vignette", // Not currently used +#endif L"%clamp%misc/shadow", -// L"/achievement/bg", // Not currently used +#ifdef ENABLE_JAVA_GUIS + L"/achievement/bg", // Not currently used +#endif L"art/kz", L"environment/clouds", L"environment/rain", L"environment/snow", L"gui/gui", +#ifdef ENABLE_JAVA_GUIS + L"gui/background", + L"gui/inventory", + L"gui/container", + L"gui/crafting", + L"gui/furnace", + L"title/mclogo", +#endif L"gui/icons", L"item/arrows", L"item/boat", diff --git a/Minecraft.Client/Textures/Textures.h b/Minecraft.Client/Textures/Textures.h index a96947384..0c8994169 100644 --- a/Minecraft.Client/Textures/Textures.h +++ b/Minecraft.Client/Textures/Textures.h @@ -17,14 +17,26 @@ class PreStitchedTextureMap; typedef enum _TEXTURE_NAME { TN__BLUR__MISC_PUMPKINBLUR, -// TN__BLUR__MISC_VIGNETTE, // Not currently used +#ifdef ENABLE_JAVA_GUIS + TN__BLUR__MISC_VIGNETTE, // Not currently used +#endif TN__CLAMP__MISC_SHADOW, -// TN_ACHIEVEMENT_BG, // Not currently used +#ifdef ENABLE_JAVA_GUIS + TN_ACHIEVEMENT_BG, // Not currently used +#endif TN_ART_KZ, TN_ENVIRONMENT_CLOUDS, TN_ENVIRONMENT_RAIN, TN_ENVIRONMENT_SNOW, TN_GUI_GUI, +#ifdef ENABLE_JAVA_GUIS + TN_GUI_BACKGROUND, + TN_GUI_INVENTORY, + TN_GUI_CONTAINER, + TN_GUI_CRAFTING, + TN_GUI_FURNACE, + TN_TITLE_MCLOGO, +#endif TN_GUI_ICONS, TN_ITEM_ARROWS, TN_ITEM_BOAT, diff --git a/Minecraft.Client/UI/Gui.cpp b/Minecraft.Client/UI/Gui.cpp index 87213ba19..c4dae6b23 100644 --- a/Minecraft.Client/UI/Gui.cpp +++ b/Minecraft.Client/UI/Gui.cpp @@ -28,7 +28,11 @@ #include "../../Minecraft.World/Level/LevelChunk.h" #include "../../Minecraft.World/WorldGen/Biomes/Biome.h" +#ifdef ENABLE_JAVA_GUIS #define RENDER_HUD 1 +#else +#define RENDER_HUD 0 +#endif // #ifndef _XBOX // #undef RENDER_HUD @@ -860,7 +864,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) lastTickA = a; // 4J Stu - This is now displayed in a xui scene -#if 0 +#ifdef ENABLE_JAVA_GUIS // Jukebox CD message if (overlayMessageTime > 0) { @@ -908,7 +912,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) glDisable(GL_ALPHA_TEST); // 4J Stu - We have moved the chat text to a xui -#if 0 +#ifdef ENABLE_JAVA_GUIS glPushMatrix(); // 4J-PB we need to move this up a bit because we've moved the quick select //glTranslatef(0, ((float)screenHeight) - 48, 0); @@ -1090,7 +1094,7 @@ void Gui::renderVignette(float br, int w, int h) if (br > 1) br = 1; tbr += (br - tbr) * 0.01f; -#if 0 // 4J - removed - TODO put back when we have blend functions implemented +#ifdef ENABLE_JAVA_GUIS // 4J - removed - TODO put back when we have blend functions implemented glDisable(GL_DEPTH_TEST); glDepthMask(false); glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); diff --git a/Minecraft.Client/UI/Screen.cpp b/Minecraft.Client/UI/Screen.cpp index 3fe91d598..ff6bee12d 100644 --- a/Minecraft.Client/UI/Screen.cpp +++ b/Minecraft.Client/UI/Screen.cpp @@ -5,6 +5,7 @@ #include "../Rendering/Tesselator.h" #include "../Textures/Textures.h" #include "../../Minecraft.World/Util/SoundTypes.h" +#include @@ -103,6 +104,47 @@ void Screen::init() void Screen::updateEvents() { +// TODO: update for SDL if we ever get around to that +#if (defined (ENABLE_JAVA_GUIS)) + int fbw, fbh; + RenderManager.GetFramebufferSize(fbw, fbh); + glViewport(0, 0, fbw, fbh); + ScreenSizeCalculator ssc(minecraft->options, minecraft->width, minecraft->height); + int screenWidth = ssc.getWidth(); + int screenHeight = ssc.getHeight(); + + GLFWwindow* window = glfwGetCurrentContext(); + if (!window) return; + + double xpos, ypos; + glfwGetCursorPos(window, &xpos, &ypos); + + int xMouse = (int)xpos * screenWidth / fbw; + int yMouse = (int)ypos * screenHeight / fbh - 1; + + static bool prevLeftState = false; + static bool prevRightState = false; + + bool leftState = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; + bool rightState = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS; + + if (leftState && !prevLeftState) { + mouseClicked(xMouse, yMouse, 0); + } + else if (!leftState && prevLeftState) { + mouseReleased(xMouse, yMouse, 0); + } + + if (rightState && !prevRightState) { + mouseClicked(xMouse, yMouse, 1); + } + else if (!rightState && prevRightState) { + mouseReleased(xMouse, yMouse, 1); + } + + prevLeftState = leftState; + prevRightState = rightState; +#else /* 4J - TODO while (Mouse.next()) { mouseEvent(); @@ -112,7 +154,7 @@ void Screen::updateEvents() keyboardEvent(); } */ - +#endif } void Screen::mouseEvent() @@ -171,6 +213,21 @@ void Screen::renderBackground(int vo) void Screen::renderDirtBackground(int vo) { // 4J Unused - Iggy Flash UI renders the background on consoles +#ifdef ENABLE_JAVA_GUIS + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + Tesselator *t = Tesselator::getInstance(); + glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN_GUI_BACKGROUND)); + glColor4f(1, 1, 1, 1); + float s = 32; + t->begin(); + t->color(0x404040); + t->vertexUV(static_cast(0), static_cast(height), static_cast(0), static_cast(0), static_cast(height / s + vo)); + t->vertexUV(static_cast(width), static_cast(height), static_cast(0), static_cast(width / s), static_cast(height / s + vo)); + t->vertexUV(static_cast(width), static_cast(0), static_cast(0), static_cast(width / s), static_cast(0 + vo)); + t->vertexUV(static_cast(0), static_cast(0), static_cast(0), static_cast(0), static_cast(0 + vo)); + t->end(); +#endif } bool Screen::isPauseScreen() diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp index 56e5ed54e..147251dc7 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp @@ -33,7 +33,7 @@ void AbstractContainerScreen::init() void AbstractContainerScreen::render(int xm, int ym, float a) { // 4J Stu - Not used -#if 0 +#if ENABLE_JAVA_GUIS renderBackground(); int xo = (width - imageWidth) / 2; int yo = (height - imageHeight) / 2; @@ -96,7 +96,8 @@ void AbstractContainerScreen::render(int xm, int ym, float a) if (inventory->getCarried() == NULL && hoveredSlot != NULL && hoveredSlot->hasItem()) { - std::wstring elementName = trimString(Language::getInstance()->getElementName(hoveredSlot->getItem()->getDescriptionId())); + // std::wstring elementName = trimString(Language::getInstance()->getElementName(hoveredSlot->getItem()->getDescriptionId())); + std::wstring elementName = L""; if (elementName.length() > 0) { @@ -125,23 +126,23 @@ void AbstractContainerScreen::renderLabels() void AbstractContainerScreen::renderSlot(Slot *slot) { // 4J Unused -#if 0 +#if ENABLE_JAVA_GUIS int x = slot->x; int y = slot->y; std::shared_ptr item = slot->getItem(); - if (item == NULL) - { - int icon = slot->getNoItemIcon(); - if (icon >= 0) - { - glDisable(GL_LIGHTING); - minecraft->textures->bind(minecraft->textures->loadTexture(TN_GUI_ITEMS));//L"/gui/items.png")); - blit(x, y, icon % 16 * 16, icon / 16 * 16, 16, 16); - glEnable(GL_LIGHTING); - return; - } - } + // if (item == NULL) + // { + // int icon = slot->getNoItemIcon(); + // if (icon >= 0) + // { + // glDisable(GL_LIGHTING); + // minecraft->textures->bind(minecraft->textures->loadTexture(TN_GUI_ITEMS));//L"/gui/items.png")); + // blit(x, y, icon % 16 * 16, icon / 16 * 16, 16, 16); + // glEnable(GL_LIGHTING); + // return; + // } + // } itemRenderer->renderGuiItem(font, minecraft->textures, item, x, y); itemRenderer->renderGuiItemDecorations(font, minecraft->textures, item, x, y); diff --git a/Minecraft.Client/UI/Screens/AchievementPopup.cpp b/Minecraft.Client/UI/Screens/AchievementPopup.cpp index 16c4e378b..b715538e2 100644 --- a/Minecraft.Client/UI/Screens/AchievementPopup.cpp +++ b/Minecraft.Client/UI/Screens/AchievementPopup.cpp @@ -73,7 +73,7 @@ void AchievementPopup::prepareWindow() void AchievementPopup::render() { // 4J Unused -#if 0 +#if ENABLE_JAVA_GUIS if (Minecraft::warezTime > 0) { glDisable(GL_DEPTH_TEST); @@ -119,7 +119,7 @@ void AchievementPopup::render() int xx = width - 160; int yy = 0 - (int) (yo * 36); - int tex = mc->textures->loadTexture(L"/achievement/bg.png"); + int tex = mc->textures->loadTexture(TN_ACHIEVEMENT_BG); glColor4f(1, 1, 1, 1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); @@ -127,15 +127,15 @@ void AchievementPopup::render() blit(xx, yy, 96, 202, 160, 32); - if (isHelper) - { - mc->font->drawWordWrap(desc, xx + 30, yy + 7, 120, 0xffffffff); - } - else - { + // if (isHelper) + // { + // mc->font->drawWordWrap(desc, xx + 30, yy + 7, 120, 0xffffffff); + // } + // else + // { mc->font->draw(title, xx + 30, yy + 7, 0xffffff00); mc->font->draw(desc, xx + 30, yy + 18, 0xffffffff); - } + // } glPushMatrix(); glRotatef(180, 1, 0, 0); diff --git a/Minecraft.Client/UI/Screens/ContainerScreen.cpp b/Minecraft.Client/UI/Screens/ContainerScreen.cpp index e3d6d1ffd..c8027ed41 100644 --- a/Minecraft.Client/UI/Screens/ContainerScreen.cpp +++ b/Minecraft.Client/UI/Screens/ContainerScreen.cpp @@ -28,8 +28,8 @@ void ContainerScreen::renderLabels() void ContainerScreen::renderBg(float a) { // 4J Unused -#if 0 - int tex = minecraft->textures->loadTexture(L"/gui/container.png"); +#ifdef ENABLE_JAVA_GUIS + int tex = minecraft->textures->loadTexture(TN_GUI_CONTAINER); glColor4f(1, 1, 1, 1); minecraft->textures->bind(tex); int xo = (width - imageWidth) / 2; diff --git a/Minecraft.Client/UI/Screens/CraftingScreen.cpp b/Minecraft.Client/UI/Screens/CraftingScreen.cpp index 8935e0191..0a3febbdf 100644 --- a/Minecraft.Client/UI/Screens/CraftingScreen.cpp +++ b/Minecraft.Client/UI/Screens/CraftingScreen.cpp @@ -23,8 +23,8 @@ void CraftingScreen::renderLabels() void CraftingScreen::renderBg(float a) { // 4J Unused -#if 0 - int tex = minecraft->textures->loadTexture(L"/gui/crafting.png"); +#ifdef ENABLE_JAVA_GUIS + int tex = minecraft->textures->loadTexture(TN_GUI_CRAFTING); glColor4f(1, 1, 1, 1); minecraft->textures->bind(tex); int xo = (width - imageWidth) / 2; diff --git a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp index 6629a420f..ad71177aa 100644 --- a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp +++ b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp @@ -9,6 +9,9 @@ #include "../../../Minecraft.World/Headers/net.minecraft.world.level.storage.h" #include "../../../Minecraft.World/Util/SharedConstants.h" #include "../../../Minecraft.World/Util/Random.h" +#include "../../MinecraftServer.h" +#include "../../GameState/Options.h" +#include CreateWorldScreen::CreateWorldScreen(Screen *lastScreen) { @@ -97,24 +100,132 @@ void CreateWorldScreen::buttonClicked(Button *button) if (done) return; done = true; - __int64 seedValue = (new Random())->nextLong(); + MoreOptionsParams* moreOptionsParams = new MoreOptionsParams(); + + // these r just the defaults from the createworldmenu UIscene + // i had higher ambitions for what id do with these but its not worth it for a temp ui + moreOptionsParams->bGenerateOptions = TRUE; + moreOptionsParams->bStructures = TRUE; + moreOptionsParams->bFlatWorld = FALSE; + moreOptionsParams->bBonusChest = FALSE; + moreOptionsParams->bPVP = TRUE; + moreOptionsParams->bTrust = TRUE; + moreOptionsParams->bFireSpreads = TRUE; + moreOptionsParams->bTNT = TRUE; + moreOptionsParams->bHostPrivileges = FALSE; + moreOptionsParams->bOnlineGame = FALSE; + moreOptionsParams->bInviteOnly = FALSE; + moreOptionsParams->bAllowFriendsOfFriends = FALSE; + moreOptionsParams->bOnlineSettingChangedBySystem = FALSE; + moreOptionsParams->iPad = 0; + + moreOptionsParams->worldName = nameEdit->getValue(); + moreOptionsParams->seed = seedEdit->getValue(); + + moreOptionsParams->dwTexturePack = 0; + + bool bGameModeSurvival = true; + + std::wstring worldName = nameEdit->getValue(); + if (worldName.empty()) + { + worldName = L"2slimey"; + } + + StorageManager.ResetSaveData(); + StorageManager.SetSaveTitle((wchar_t *)worldName.c_str()); + std::wstring seedString = seedEdit->getValue(); + + __int64 seedValue = 0; + NetworkGameInitData *param = new NetworkGameInitData(); if (seedString.length() != 0) { // try to convert it to a long first // try { // 4J - removed try/catch __int64 value = _fromString<__int64>(seedString); + + bool isNumber = true; + for (unsigned int i = 0; i < seedString.length(); ++i) + { + if (seedString.at(i) < L'0' || seedString.at(i) > L'9') + { + if (!(i == 0 && seedString.at(i) == L'-')) + { + isNumber = false; + break; + } + } + } + + if (isNumber) + value = _fromString<__int64>(seedString); + if (value != 0) { seedValue = value; } + else + { + int hashValue = 0; + for (unsigned int i = 0; i < seedString.length(); ++i) + hashValue = 31 * hashValue + seedString.at(i); + seedValue = hashValue; + } // } catch (NumberFormatException e) { // // not a number, fetch hash value // seedValue = seedString.hashCode(); // } } + else + { + param->findSeed = true; + } + param->seed = seedValue; + param->saveData = NULL; + param->texturePackId = 0; + param->settings = 0; + + app.SetGameHostOption(eGameHostOption_Difficulty, minecraft->options->difficulty); + app.SetGameHostOption(eGameHostOption_FriendsOfFriends, moreOptionsParams->bAllowFriendsOfFriends); + app.SetGameHostOption(eGameHostOption_Gamertags, 1); + app.SetGameHostOption(eGameHostOption_BedrockFog, 0); + app.SetGameHostOption(eGameHostOption_GameType, bGameModeSurvival ? GameType::SURVIVAL->getId() : GameType::CREATIVE->getId()); // TODO: gamemode switch + app.SetGameHostOption(eGameHostOption_LevelType, moreOptionsParams->bFlatWorld); + app.SetGameHostOption(eGameHostOption_Structures, moreOptionsParams->bStructures); + app.SetGameHostOption(eGameHostOption_BonusChest, moreOptionsParams->bBonusChest); + app.SetGameHostOption(eGameHostOption_PvP, moreOptionsParams->bPVP); + app.SetGameHostOption(eGameHostOption_TrustPlayers, moreOptionsParams->bTrust); + app.SetGameHostOption(eGameHostOption_FireSpreads, moreOptionsParams->bFireSpreads); + app.SetGameHostOption(eGameHostOption_TNT, moreOptionsParams->bTNT); + app.SetGameHostOption(eGameHostOption_HostCanFly, moreOptionsParams->bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, moreOptionsParams->bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, moreOptionsParams->bHostPrivileges); + + param->settings = app.GetGameHostOption(eGameHostOption_All); + param->xzSize = LEVEL_MAX_WIDTH; + param->hellScale = HELL_LEVEL_MAX_SCALE; + + g_NetworkManager.HostGame(0, false, false, MINECRAFT_NET_MAX_PLAYERS, 0); + + g_NetworkManager.FakeLocalPlayerJoined(); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + app.SetAutosaveTimerTime(); + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground = TRUE; + completionData->bShowLogo = TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = 0; + loadingParams->completionData = completionData; + + ui.NavigateToScene(0, eUIScene_FullscreenProgress, loadingParams); // 4J Stu - This screen is not used, so removing this to stop the build failing #if 0 minecraft->gameMode = new SurvivalMode(minecraft); diff --git a/Minecraft.Client/UI/Screens/CreateWorldScreen.h b/Minecraft.Client/UI/Screens/CreateWorldScreen.h index 96ca5b113..d2d7bcea8 100644 --- a/Minecraft.Client/UI/Screens/CreateWorldScreen.h +++ b/Minecraft.Client/UI/Screens/CreateWorldScreen.h @@ -29,4 +29,36 @@ protected: public: virtual void render(int xm, int ym, float a); virtual void tabPressed(); + +private: + int m_iGameModeId; + bool m_bGameModeCreative; + + struct MoreOptionsParams + { + bool bGenerateOptions; + bool bStructures; + bool bFlatWorld; + bool bBonusChest; + bool bPVP; + bool bTrust; + bool bFireSpreads; + bool bHostPrivileges; + bool bTNT; + bool bMobGriefing; + bool bKeepInventory; + bool bDoMobSpawning; + bool bDoMobLoot; + bool bDoTileDrops; + bool bNaturalRegeneration; + bool bDoDaylightCycle; + bool bOnlineGame; + bool bInviteOnly; + bool bAllowFriendsOfFriends; + bool bOnlineSettingChangedBySystem; + int dwTexturePack; + int iPad; + std::wstring worldName; + std::wstring seed; + } m_MoreOptionsParams; }; \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/FurnaceScreen.cpp b/Minecraft.Client/UI/Screens/FurnaceScreen.cpp index 20d19c04c..3b1409390 100644 --- a/Minecraft.Client/UI/Screens/FurnaceScreen.cpp +++ b/Minecraft.Client/UI/Screens/FurnaceScreen.cpp @@ -20,8 +20,8 @@ void FurnaceScreen::renderLabels() void FurnaceScreen::renderBg(float a) { // 4J Unused -#if 0 - int tex = minecraft->textures->loadTexture(L"/gui/furnace.png"); +#ifdef ENABLE_JAVA_GUIS + int tex = minecraft->textures->loadTexture(TN_GUI_FURNACE); glColor4f(1, 1, 1, 1); minecraft->textures->bind(tex); int xo = (width - imageWidth) / 2; diff --git a/Minecraft.Client/UI/Screens/InventoryScreen.cpp b/Minecraft.Client/UI/Screens/InventoryScreen.cpp index 61dd3f139..841eeb4e5 100644 --- a/Minecraft.Client/UI/Screens/InventoryScreen.cpp +++ b/Minecraft.Client/UI/Screens/InventoryScreen.cpp @@ -38,8 +38,8 @@ void InventoryScreen::render(int xm, int ym, float a) void InventoryScreen::renderBg(float a) { // 4J Unused -#if 0 - int tex = minecraft->textures->loadTexture(L"/gui/inventory.png"); +#ifdef ENABLE_JAVA_GUIS + int tex = minecraft->textures->loadTexture(TN_GUI_INVENTORY); glColor4f(1, 1, 1, 1); minecraft->textures->bind(tex); int xo = (width - imageWidth) / 2; diff --git a/Minecraft.Client/UI/Screens/PauseScreen.cpp b/Minecraft.Client/UI/Screens/PauseScreen.cpp index 759c2b1fc..5fafa8561 100644 --- a/Minecraft.Client/UI/Screens/PauseScreen.cpp +++ b/Minecraft.Client/UI/Screens/PauseScreen.cpp @@ -9,6 +9,8 @@ #include "../../../Minecraft.World/Headers/net.minecraft.world.level.h" #include "../../../Minecraft.World/Headers/net.minecraft.stats.h" #include "../../Player/LocalPlayer.h" +#include "../../Player/MultiPlayerLocalPlayer.h" +#include "../../MinecraftServer.h" PauseScreen::PauseScreen() { @@ -41,33 +43,34 @@ void PauseScreen::init() } -void PauseScreen::buttonClicked(Button button) +void PauseScreen::buttonClicked(Button* button) { - if (button.id == 0) + if (button->id == 0) { minecraft->setScreen(new OptionsScreen(this, minecraft->options)); } - if (button.id == 1) + if (button->id == 1) { - if (minecraft->isClientSide()) - { - minecraft->level->disconnect(); - } + // TODO: proper disconnects + // if (minecraft->isClientSide()) + // { + // minecraft->level->disconnect(); + // } - minecraft->setLevel(NULL); - minecraft->setScreen(new TitleScreen()); + // minecraft->setLevel(NULL); + // minecraft->setScreen(new TitleScreen()); } - if (button.id == 4) + if (button->id == 4) { minecraft->setScreen(NULL); // minecraft->grabMouse(); // 4J - removed } - if (button.id == 5) + if (button->id == 5) { // minecraft->setScreen(new AchievementScreen(minecraft->stats)); // 4J TODO - put back } - if (button.id == 6) + if (button->id == 6) { // minecraft->setScreen(new StatsScreen(this, minecraft->stats)); // 4J TODO - put back } diff --git a/Minecraft.Client/UI/Screens/PauseScreen.h b/Minecraft.Client/UI/Screens/PauseScreen.h index 4603947fa..0f6cc8bf9 100644 --- a/Minecraft.Client/UI/Screens/PauseScreen.h +++ b/Minecraft.Client/UI/Screens/PauseScreen.h @@ -11,7 +11,7 @@ public: virtual void init(); protected:using Screen::buttonClicked; - virtual void buttonClicked(Button button); + virtual void buttonClicked(Button* button); public: virtual void tick(); virtual void render(int xm, int ym, float a); diff --git a/Minecraft.Client/UI/Screens/TitleScreen.cpp b/Minecraft.Client/UI/Screens/TitleScreen.cpp index 09889b5f4..e9948e408 100644 --- a/Minecraft.Client/UI/Screens/TitleScreen.cpp +++ b/Minecraft.Client/UI/Screens/TitleScreen.cpp @@ -10,6 +10,7 @@ #include "../../../Minecraft.World/Headers/net.minecraft.locale.h" #include "../../../Minecraft.World/Platform/System.h" #include "../../../Minecraft.World/Util/Random.h" +#include #include "TitleScreen.h" Random *TitleScreen::random = new Random(); @@ -20,7 +21,7 @@ TitleScreen::TitleScreen() vo = 0; multiplayerButton = NULL; - splash = L"missingno"; + splash = L"4JCraft!"; // try { // 4J - removed try/catch std::vector splashes; @@ -41,7 +42,7 @@ TitleScreen::TitleScreen() delete br; */ - splash = L""; //splashes.at(random->nextInt(splashes.size())); + //splash = L""; //splashes.at(random->nextInt(splashes.size())); // } catch (Exception e) { // } @@ -127,4 +128,34 @@ void TitleScreen::buttonClicked(Button *button) void TitleScreen::render(int xm, int ym, float a) { // 4J Unused - Iggy Flash UI renders the title screen on consoles +#ifdef ENABLE_JAVA_GUIS + renderBackground(); + Tesselator *t = Tesselator::getInstance(); + + int logoWidth = 155 + 119; + int logoX = width / 2 - logoWidth / 2; + int logoY = 30; + + glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN_TITLE_MCLOGO)); + glColor4f(1, 1, 1, 1); + blit(logoX + 0, logoY + 0, 0, 0, 155, 44); + blit(logoX + 155, logoY + 0, 0, 45, 155, 44); + t->color(0xffffff); + glPushMatrix(); + glTranslatef((float)width / 2 + 90, 70, 0); + + glRotatef(-20, 0, 0, 1); + float sss = 1.8f - Mth::abs(Mth::sin(System::currentTimeMillis() % 1000 / 1000.0f * PI * 2) * 0.1f); + + sss = sss * 100 / (font->width(splash) + 8 * 4); + glScalef(sss, sss, sss); + drawCenteredString(font, splash, 0, -8, 0xffff00); + glPopMatrix(); + + drawString(font, ClientConstants::VERSION_STRING, 2, 2, 0x505050); + wstring msg = L"Copyright Mojang AB. Do not distribute."; + drawString(font, msg, width - font->width(msg) - 2, height - 10, 0xffffff); + + Screen::render(xm, ym, a); +#endif } diff --git a/meson.build b/meson.build index 3cc9b0c41..fbec8dca4 100644 --- a/meson.build +++ b/meson.build @@ -38,6 +38,10 @@ global_cpp_defs = [ '-DDEBUG', ] +if get_option('enable_java_guis') + global_cpp_defs += '-DENABLE_JAVA_GUIS' +endif + if host_machine.system() == 'linux' global_cpp_defs += [ '-Dlinux', diff --git a/meson.options b/meson.options new file mode 100644 index 000000000..4e0b87ec5 --- /dev/null +++ b/meson.options @@ -0,0 +1,4 @@ +option('enable_java_guis', + type : 'boolean', + value : false, + description : 'Re-enable the Java UI remnants in the code (for testing only)') \ No newline at end of file From 48f31b3e8f9b2b766d0aeeccbe70a47a9eb910e7 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 22:30:57 -0500 Subject: [PATCH 02/29] feat: default to true for enable_java_guis Co-Authored-By: ffqq <36998498+realffqq@users.noreply.github.com> --- meson.options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.options b/meson.options index 4e0b87ec5..58cbbbf01 100644 --- a/meson.options +++ b/meson.options @@ -1,4 +1,4 @@ option('enable_java_guis', type : 'boolean', - value : false, + value : true, description : 'Re-enable the Java UI remnants in the code (for testing only)') \ No newline at end of file From 0a286d4ddca22531839d3bce3f937b5cd93035ee Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 22:47:16 -0500 Subject: [PATCH 03/29] refactor: modify `ClientConstants::VERSION_STRING` to list 4jcraft Co-Authored-By: ffqq <36998498+realffqq@users.noreply.github.com> --- Minecraft.Client/ClientConstants.cpp | 2 +- Minecraft.Client/UI/Screens/TitleScreen.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/ClientConstants.cpp b/Minecraft.Client/ClientConstants.cpp index 55a7ab0ad..118497b6f 100644 --- a/Minecraft.Client/ClientConstants.cpp +++ b/Minecraft.Client/ClientConstants.cpp @@ -1,4 +1,4 @@ #include "Platform/stdafx.h" #include "ClientConstants.h" -const std::wstring ClientConstants::VERSION_STRING = std::wstring(L"Minecraft Xbox ") + VER_FILEVERSION_STR_W;//+ SharedConstants::VERSION_STRING; \ No newline at end of file +const std::wstring ClientConstants::VERSION_STRING = std::wstring(L"Minecraft Xbox ") + VER_FILEVERSION_STR_W + std::wstring(L" (4jcraft)");//+ SharedConstants::VERSION_STRING; \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/TitleScreen.cpp b/Minecraft.Client/UI/Screens/TitleScreen.cpp index e9948e408..4ec4e3893 100644 --- a/Minecraft.Client/UI/Screens/TitleScreen.cpp +++ b/Minecraft.Client/UI/Screens/TitleScreen.cpp @@ -21,7 +21,7 @@ TitleScreen::TitleScreen() vo = 0; multiplayerButton = NULL; - splash = L"4JCraft!"; + splash = L"missingno"; // try { // 4J - removed try/catch std::vector splashes; From f0aa04a7ee32ff36d04cfa5a92f4f887cf37f1d1 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:07:42 -0500 Subject: [PATCH 04/29] fix: compute logical mouse position using window scale factor Fixes mouse support in menus on systems with scaling factors other than 1.0x --- Minecraft.Client/UI/Screen.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Minecraft.Client/UI/Screen.cpp b/Minecraft.Client/UI/Screen.cpp index ff6bee12d..1bac8ed36 100644 --- a/Minecraft.Client/UI/Screen.cpp +++ b/Minecraft.Client/UI/Screen.cpp @@ -54,7 +54,7 @@ void Screen::mouseClicked(int x, int y, int buttonNum) { if (buttonNum == 0) { - AUTO_VAR(itEnd, buttons.end()); + AUTO_VAR(itEnd, buttons.end()); for (AUTO_VAR(it, buttons.begin()); it != itEnd; it++) { Button *button = *it; //buttons[i]; @@ -116,11 +116,15 @@ void Screen::updateEvents() GLFWwindow* window = glfwGetCurrentContext(); if (!window) return; + float windowScaleX = 1; + float windowScaleY = 1; + glfwGetWindowContentScale(window, &windowScaleX, &windowScaleY); + double xpos, ypos; glfwGetCursorPos(window, &xpos, &ypos); - int xMouse = (int)xpos * screenWidth / fbw; - int yMouse = (int)ypos * screenHeight / fbh - 1; + int xMouse = (int)(xpos * windowScaleX) * screenWidth / fbw; + int yMouse = (int)(ypos * windowScaleY) * screenHeight / fbh - 1; static bool prevLeftState = false; static bool prevRightState = false; From c4ce9b53770d8e895f91c44e0512ad2989f43cfd Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:41:56 -0500 Subject: [PATCH 05/29] refactor: use InputManager for screens, DPI-aware InputManager --- 4J.Input/4J_Input.cpp | 47 ++++++++++++++++++++-------------- Minecraft.Client/UI/Button.cpp | 1 - Minecraft.Client/UI/Screen.cpp | 33 +++++++++--------------- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index 8f6f880a8..4aadc69ea 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -61,13 +61,21 @@ static GLFWwindow *getWindow() { // GLFW callbacks // --------------------------------------------------------------------------- -static void onCursorPos(GLFWwindow * /*w*/, double x, double y) { +static void onCursorPos(GLFWwindow* w, double x, double y) { + float scaleX = 1; + float scaleY = 1; + glfwGetWindowContentScale(w, &scaleX, &scaleY); + + x *= scaleX; + y *= scaleX; + if (s_cursorInitialized) { s_mouseAccumX += (float)(x - s_lastCursorX); s_mouseAccumY += (float)(y - s_lastCursorY); } else { s_cursorInitialized = true; } + s_lastCursorX = x; s_lastCursorY = y; } @@ -208,24 +216,25 @@ void C_4JInput::Tick(void) { s_mouseAccumX = s_mouseAccumY = 0.0f; // 6. Mouse buttons (only meaningful when locked in-game) - if (s_mouseLocked) { - s_mouseLeftCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - s_mouseRightCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - } else { - // Not locked. Allow a left-click to re-lock (if not in a menu) - bool lclick = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - if (!menuNow && lclick) { - s_mouseLocked = true; - glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - if (glfwRawMouseMotionSupported()) - glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); - s_mouseAccumX = s_mouseAccumY = 0.0f; - s_cursorInitialized = false; - } - s_mouseLeftCurrent = false; - s_mouseRightCurrent = false; - s_frameRelX = s_frameRelY = 0.0f; - } + s_mouseLeftCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); + s_mouseRightCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); + // if (s_mouseLocked) { + // printf("locked\n"); + // } else { + // // Not locked. Allow a left-click to re-lock (if not in a menu) + // bool lclick = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); + // if (!menuNow && lclick) { + // s_mouseLocked = true; + // glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + // if (glfwRawMouseMotionSupported()) + // glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); + // s_mouseAccumX = s_mouseAccumY = 0.0f; + // s_cursorInitialized = false; + // } + // s_mouseLeftCurrent = false; + // s_mouseRightCurrent = false; + // s_frameRelX = s_frameRelY = 0.0f; + // } } // --------------------------------------------------------------------------- diff --git a/Minecraft.Client/UI/Button.cpp b/Minecraft.Client/UI/Button.cpp index d3cfe3e3b..484c7438c 100644 --- a/Minecraft.Client/UI/Button.cpp +++ b/Minecraft.Client/UI/Button.cpp @@ -44,7 +44,6 @@ void Button::render(Minecraft *minecraft, int xm, int ym) glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN_GUI_GUI)); // 4J was L"/gui/gui.png" glColor4f(1, 1, 1, 1); - bool hovered = xm >= x && ym >= y && xm < x + w && ym < y + h; int yImage = getYImage(hovered); diff --git a/Minecraft.Client/UI/Screen.cpp b/Minecraft.Client/UI/Screen.cpp index 1bac8ed36..f66e14953 100644 --- a/Minecraft.Client/UI/Screen.cpp +++ b/Minecraft.Client/UI/Screen.cpp @@ -106,32 +106,23 @@ void Screen::updateEvents() { // TODO: update for SDL if we ever get around to that #if (defined (ENABLE_JAVA_GUIS)) - int fbw, fbh; - RenderManager.GetFramebufferSize(fbw, fbh); - glViewport(0, 0, fbw, fbh); + int fbw, fbh; + RenderManager.GetFramebufferSize(fbw, fbh); + glViewport(0, 0, fbw, fbh); ScreenSizeCalculator ssc(minecraft->options, minecraft->width, minecraft->height); - int screenWidth = ssc.getWidth(); - int screenHeight = ssc.getHeight(); - - GLFWwindow* window = glfwGetCurrentContext(); - if (!window) return; - - float windowScaleX = 1; - float windowScaleY = 1; - glfwGetWindowContentScale(window, &windowScaleX, &windowScaleY); - - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - int xMouse = (int)(xpos * windowScaleX) * screenWidth / fbw; - int yMouse = (int)(ypos * windowScaleY) * screenHeight / fbh - 1; + int screenWidth = ssc.getWidth(); + int screenHeight = ssc.getHeight(); + int xMouse = InputManager.GetMouseX() * screenWidth / fbw; + int yMouse = InputManager.GetMouseY() * screenHeight / fbh - 1; static bool prevLeftState = false; static bool prevRightState = false; + + bool leftState = InputManager.ButtonDown(0, MINECRAFT_ACTION_ACTION); + bool rightState = InputManager.ButtonDown(0, MINECRAFT_ACTION_USE); - bool leftState = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; - bool rightState = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS; - + printf("%d, %d\n", leftState, rightState); + if (leftState && !prevLeftState) { mouseClicked(xMouse, yMouse, 0); } From fc2a548f3e9f07790adad08a5f3d1746e022a22b Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:57:48 -0500 Subject: [PATCH 06/29] refactor: get rid of the FPS flamegraph --- Minecraft.Client/Minecraft.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 5684c065b..4e5e6f7ac 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1899,7 +1899,6 @@ void Minecraft::run_middle() Sleep(10); } */ - renderFpsMeter(tickDuraction); if (options->renderDebug) { From 3f8f7795f93a54eefd45f4136fc5de9942a15cbd Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Tue, 10 Mar 2026 00:57:06 -0500 Subject: [PATCH 07/29] fix: display a blank screen while the world loads --- 4J.Input/4J_Input.cpp | 17 ----------------- .../UI/Screens/CreateWorldScreen.cpp | 3 +-- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index 4aadc69ea..99ed54adb 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -218,23 +218,6 @@ void C_4JInput::Tick(void) { // 6. Mouse buttons (only meaningful when locked in-game) s_mouseLeftCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); s_mouseRightCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - // if (s_mouseLocked) { - // printf("locked\n"); - // } else { - // // Not locked. Allow a left-click to re-lock (if not in a menu) - // bool lclick = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - // if (!menuNow && lclick) { - // s_mouseLocked = true; - // glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // if (glfwRawMouseMotionSupported()) - // glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); - // s_mouseAccumX = s_mouseAccumY = 0.0f; - // s_cursorInitialized = false; - // } - // s_mouseLeftCurrent = false; - // s_mouseRightCurrent = false; - // s_frameRelX = s_frameRelY = 0.0f; - // } } // --------------------------------------------------------------------------- diff --git a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp index ad71177aa..daf4cd29d 100644 --- a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp +++ b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp @@ -95,8 +95,7 @@ void CreateWorldScreen::buttonClicked(Button *button) } else if (button->id == 0) { - // note: code copied from SelectWorldScreen - minecraft->setScreen(NULL); + minecraft->setScreen(new Screen()); // blank screen while the world loads if (done) return; done = true; From 716fa4fc21c6b45f3c28a89f956377610a9d3444 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Tue, 10 Mar 2026 16:49:50 +0300 Subject: [PATCH 08/29] fix: pass ESC keypress to screen (#161) --- Minecraft.Client/Minecraft.cpp | 4 +++- Minecraft.Client/UI/Screen.h | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 4e5e6f7ac..0f74ad0db 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -2106,7 +2106,9 @@ void Minecraft::pauseGame() { if (screen != NULL) { - setScreen(NULL); + // 4jcraft: Pass the keypress to the screen + // normally this would've been done in updateEvents(), but it works better here (for now atleast) + screen->keyPressed(0, Keyboard::KEY_ESCAPE); return; } #ifdef ENABLE_JAVA_GUIS diff --git a/Minecraft.Client/UI/Screen.h b/Minecraft.Client/UI/Screen.h index 169b49f33..c4a70736b 100644 --- a/Minecraft.Client/UI/Screen.h +++ b/Minecraft.Client/UI/Screen.h @@ -23,10 +23,9 @@ public: Screen(); // 4J added virtual void render(int xm, int ym, float a); -protected: - virtual void keyPressed(wchar_t eventCharacter, int eventKey); public: - static std::wstring getClipboard(); + virtual void keyPressed(wchar_t eventCharacter, int eventKey); + static std::wstring getClipboard(); static void setClipboard(const std::wstring& str); private: Button *clickedButton; From 8ae9e62be3f219a3d2429d54035fabb866c6a8bd Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Tue, 10 Mar 2026 21:14:19 -0500 Subject: [PATCH 09/29] feat: reimplement absolute mouse input on SDL --- 4J.Input/4J_Input.cpp | 12 +++++++++++- 4J.Input/4J_Input.h | 4 ++-- Minecraft.Client/UI/Screen.cpp | 2 -- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index 2ed4de5e4..f79180bf3 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -21,6 +21,7 @@ static bool s_prevMenuDisplayed = false; static bool s_snapTaken = false; static float s_accumRelX = 0, s_accumRelY = 0; static float s_snapRelX = 0, s_snapRelY = 0; +static int s_mouseX = 0, s_mouseY = 0; static int s_scrollTicksForButtonPressed = 0; static int s_scrollTicksForGetValue = 0; @@ -143,7 +144,7 @@ void C_4JInput::Tick() { if (sc > 0 && sc < KEY_COUNT) s_keysCurrent[sc] = state[sc] != 0; } - Uint32 btns = SDL_GetMouseState(NULL, NULL); + Uint32 btns = SDL_GetMouseState(&s_mouseX, &s_mouseY); s_mouseLeftCurrent = (btns & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; s_mouseRightCurrent = (btns & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; @@ -300,6 +301,15 @@ float C_4JInput::GetJoypadStick_RY(int, bool) { unsigned char C_4JInput::GetJoypadLTrigger(int, bool) { return s_mouseRightCurrent ? 255 : 0; } unsigned char C_4JInput::GetJoypadRTrigger(int, bool) { return s_mouseLeftCurrent ? 255 : 0; } + +int C_4JInput::GetMouseX() { + return s_mouseX; +} +int C_4JInput::GetMouseY() { + return s_mouseY; +} + + // We detect if a Menu is visible on the player's screen to the mouse being stuck. void C_4JInput::SetMenuDisplayed(int iPad, bool bVal) { if (iPad >= 0 && iPad < 4) s_menuDisplayed[iPad] = bVal; diff --git a/4J.Input/4J_Input.h b/4J.Input/4J_Input.h index 6fbe0006c..565fa08c4 100644 --- a/4J.Input/4J_Input.h +++ b/4J.Input/4J_Input.h @@ -134,8 +134,8 @@ public: //bool InputDetected(DWORD dwUserIndex,WCHAR *pwchInput); - float GetMouseX(); - float GetMouseY(); + int GetMouseX(); + int GetMouseY(); }; // Singleton diff --git a/Minecraft.Client/UI/Screen.cpp b/Minecraft.Client/UI/Screen.cpp index f66e14953..b9162e89f 100644 --- a/Minecraft.Client/UI/Screen.cpp +++ b/Minecraft.Client/UI/Screen.cpp @@ -121,8 +121,6 @@ void Screen::updateEvents() bool leftState = InputManager.ButtonDown(0, MINECRAFT_ACTION_ACTION); bool rightState = InputManager.ButtonDown(0, MINECRAFT_ACTION_USE); - printf("%d, %d\n", leftState, rightState); - if (leftState && !prevLeftState) { mouseClicked(xMouse, yMouse, 0); } From 9acefd2cc6ef3dd0de9e84f1a7cf6252753c2361 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Wed, 11 Mar 2026 01:27:02 -0500 Subject: [PATCH 10/29] fix: hotbar selection indicator being chopped off at the bottom --- Minecraft.Client/UI/Gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/UI/Gui.cpp b/Minecraft.Client/UI/Gui.cpp index c4dae6b23..e6e58af74 100644 --- a/Minecraft.Client/UI/Gui.cpp +++ b/Minecraft.Client/UI/Gui.cpp @@ -318,12 +318,12 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // 4J-PB - move into the safe zone, and account for 2 player splitscreen blit(iWidthOffset + (screenWidth - quickSelectWidth)/2, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset , 0, 0, 182, 22); - blit(iWidthOffset + (screenWidth - quickSelectWidth)/2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 22); + blit(iWidthOffset + (screenWidth - quickSelectWidth)/2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 24); } else { blit(iWidthOffset + screenWidth / 2 - quickSelectWidth / 2, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset , 0, 0, 182, 22); - blit(iWidthOffset + screenWidth / 2 - quickSelectWidth / 2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 22); + blit(iWidthOffset + screenWidth / 2 - quickSelectWidth / 2 - 1 + inventory->selected * 20, iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 1, 0, 22, 24, 24); } From 10a1095ab2e535ddb56c9fd5a411cb21a475199b Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Thu, 12 Mar 2026 02:07:36 +0300 Subject: [PATCH 11/29] fix: add proper head movement to player inventory preview --- Minecraft.Client/UI/Screens/InventoryScreen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Minecraft.Client/UI/Screens/InventoryScreen.cpp b/Minecraft.Client/UI/Screens/InventoryScreen.cpp index 841eeb4e5..355e2b0a8 100644 --- a/Minecraft.Client/UI/Screens/InventoryScreen.cpp +++ b/Minecraft.Client/UI/Screens/InventoryScreen.cpp @@ -58,6 +58,8 @@ void InventoryScreen::renderBg(float a) float oybr = minecraft->player->yBodyRot; float oyr = minecraft->player->yRot; float oxr = minecraft->player->xRot; + float oyh = minecraft->player->yHeadRot; + float oyhp = minecraft->player->yHeadRotO; float xd = (xo + 51) - xMouse; float yd = (yo + 75 - 50) - yMouse; @@ -71,12 +73,16 @@ void InventoryScreen::renderBg(float a) minecraft->player->yBodyRot = (float) atan(xd / 40.0f) * 20; minecraft->player->yRot = (float) atan(xd / 40.0f) * 40; minecraft->player->xRot = -(float) atan(yd / 40.0f) * 20; + minecraft->player->yHeadRot = (float) atan(xd / 40.0f) * 40; + minecraft->player->yHeadRotO = (float) atan(xd / 40.0f) * 40; glTranslatef(0, minecraft->player->heightOffset, 0); EntityRenderDispatcher::instance->playerRotY = 180; EntityRenderDispatcher::instance->render(minecraft->player, 0, 0, 0, 0, 1); minecraft->player->yBodyRot = oybr; minecraft->player->yRot = oyr; minecraft->player->xRot = oxr; + minecraft->player->yHeadRot = oyh; + minecraft->player->yHeadRotO = oyhp; glPopMatrix(); Lighting::turnOff(); glDisable(GL_RESCALE_NORMAL); From 5525aac9d5b08de7b2975b9217b946cffb0f45da Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Thu, 12 Mar 2026 16:07:16 +0300 Subject: [PATCH 12/29] fix: reorder and correct lighting for blocks in container screens --- Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp index 147251dc7..13376b7d7 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp @@ -42,7 +42,6 @@ void AbstractContainerScreen::render(int xm, int ym, float a) glPushMatrix(); glRotatef(120, 1, 0, 0); - Lighting::turnOn(); glPopMatrix(); glPushMatrix(); @@ -50,6 +49,7 @@ void AbstractContainerScreen::render(int xm, int ym, float a) glColor4f(1, 1, 1, 1); glEnable(GL_RESCALE_NORMAL); + Lighting::turnOnGui(); Slot *hoveredSlot = NULL; @@ -85,8 +85,8 @@ void AbstractContainerScreen::render(int xm, int ym, float a) itemRenderer->renderGuiItemDecorations(font, minecraft->textures, inventory->getCarried(), xm - xo - 8, ym - yo - 8); // carriedSlot = old; } - glDisable(GL_RESCALE_NORMAL); Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); From 8e26b471ea364f7b2e29823de0c9727bda0d72f5 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Thu, 12 Mar 2026 22:13:08 +0300 Subject: [PATCH 13/29] fix: remove unused GLFW include was causing CI failure --- Minecraft.Client/UI/Screen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Minecraft.Client/UI/Screen.cpp b/Minecraft.Client/UI/Screen.cpp index b9162e89f..bb35bb231 100644 --- a/Minecraft.Client/UI/Screen.cpp +++ b/Minecraft.Client/UI/Screen.cpp @@ -5,7 +5,6 @@ #include "../Rendering/Tesselator.h" #include "../Textures/Textures.h" #include "../../Minecraft.World/Util/SoundTypes.h" -#include From 66fb0f1a962de310f568504924be937afb6bfd7f Mon Sep 17 00:00:00 2001 From: lotaviods Date: Fri, 13 Mar 2026 01:00:52 -0300 Subject: [PATCH 14/29] feat: Implement creative inventory --- .../gui/creative_inventory/tab_inventory.png | Bin 0 -> 1125 bytes .../creative_inventory/tab_item_search.png | Bin 0 -> 1005 bytes .../gui/creative_inventory/tab_items.png | Bin 0 -> 965 bytes .../res/1_2_2/gui/creative_inventory/tabs.png | Bin 0 -> 1723 bytes Minecraft.Client/Minecraft.cpp | 8 +- .../Common/UI/IUIScene_CreativeMenu.h | 3 + Minecraft.Client/Textures/Textures.cpp | 4 + Minecraft.Client/Textures/Textures.h | 4 + .../UI/Screens/AbstractContainerScreen.h | 6 +- .../UI/Screens/CreativeInventoryScreen.cpp | 527 ++++++++++++++++++ .../UI/Screens/CreativeInventoryScreen.h | 71 +++ 11 files changed, 620 insertions(+), 3 deletions(-) create mode 100644 Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_inventory.png create mode 100644 Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_item_search.png create mode 100644 Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_items.png create mode 100644 Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tabs.png create mode 100644 Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp create mode 100644 Minecraft.Client/UI/Screens/CreativeInventoryScreen.h diff --git a/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_inventory.png b/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_inventory.png new file mode 100644 index 0000000000000000000000000000000000000000..f328206c0245b74d3669ac70fcdcec12b4e4079c GIT binary patch literal 1125 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJD19Zwg>kcwMx?*@9kb`WWJ zsIpq?EL)7j?{{KMu?^fBDct+E-}Y!;eae(ES2O5}Wd7wj@0&jtO*|;}e7~n^a_Ai1 zV=Qw%vq`iS1ka8C9Uvi`yG~ia_v^-=ii;4v5XK zQ}`fyK*+>*vQ6yu)aY!#`=^gbZMebEV>a9O(wnl~=eORwcki9m^!wiDuCq?v&cMPT zz~BIKH3s7cum3K`584d=yBebznu<*3GNkODB(a_?=-BID|4(h&qRgrg8+$$ST=(Z) zSd3_}j(XMXDmTN4VPED-ezD2~E|3)w9t_j|Es^Fpz&o#mc{@V`0|OHS2ZI6{;|QjTaWFJEIGJoicbI^Bm=?zp7 z1%HMjS(i-N*A^$fFftd|$aP=Mnria(z)o>A@A_n0hJ9<%ae`6P+qD0F9j=4zOn zwdS$Qf&+{NLA|AOI7I%49q=^0R;V=LJl60;cF2ryhB+b0vg%B%d=9bKUGINCnJoKy z2~Qp)I3j-hW`M+Bsw{Qdm-IotlNKlS&EF)Dblg*A z)#q72Vs(N73{CkUQtaKQI{V{5Q$g|KGbb#2uH{@Vo4JA?K20+DqX2VA*{KcD;FQx4 zpLIKo;okBZ^Sk1``5lIVZJ$LQcE+vWE8S9JA+yX@;IG&Mnfn~ci+rz~wP#I`XnU08 zmCSVR%jfsb4%ky3a!6rGS~$`x1LFrV90>|N?yw~~>}o(kfHjR`S5Ay#97giLmKWXM VQ^B~kY9a#=c)I$ztaD0e0sx9rIaL4v literal 0 HcmV?d00001 diff --git a/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_item_search.png b/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_item_search.png new file mode 100644 index 0000000000000000000000000000000000000000..be178b743a2c901d9882b068275747d6e0853bbe GIT binary patch literal 1005 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJFdEuJopAr-gY-U;m5l_PQ> zu{2O{XKz%;1tTW$pxXx1pDt10yZhAo+U+^d8;d{3%KUKud*a8lkfTWkY7cbe8xlFp zuYSsx=Sp65wwPtn%4hucE+zZ#JG(Ea`o~{;Us^cr);3+g<-s>NLe9(A#ToBwJhSa` z>0I+$yZ14E*mXBA-E7Y1pKpBC7#bKDm>4)16p$G?DgW%Ro+)c)NLjruyFTP|+e2r@ zj9F@x$LybNI6iNRZT-i6U))`__cO}$A73(a|FN6N{-@?$`M&fxXFtRk3=~2Q3{u39}J`0A@Sn=BX>ixFgmhi|i zg4NuxWAMGK;(xvL+l|Rv+WG643)Wtf3vaY#!r}(BtoP< gJhovs@<)_?$p3rO>Yd!y0<$rLr>mdKI;Vst0BXzrt^fc4 literal 0 HcmV?d00001 diff --git a/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_items.png b/Minecraft.Assets/Common/res/1_2_2/gui/creative_inventory/tab_items.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6fbb9c3fe931652d714e1c0af02261647e4d8e GIT binary patch literal 965 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJFd9#0p?kcwMx?*wMO3J_>` zsIpqLj*|ZW2In^$W~NEBJu9$S((Ca3$3u3ZdS(U|1_1^K zkQ2}t4d?kB?tgzMdHkYWwNrK6$9;b?`x*WmtlQ6j_G87CAjgOqAE+WLv>Dc2y%qd8^g;T!Pc95GtG6ycw)(*N zcSn`Mu`%JA0S{Bb+;3TxcDwc}97~bBme26EZ1>l!373A>#Mv?5lxMtkn>*2G+sR)K z>mOE3NcXt_X%=rPrO0{;FGiff8VXl0p*}?kTiU;c$be&@dY}` zsn~fU1-GPHSsvk(komG@9U73>yeg$LAh7%&52*Q>ry%kj}w9jk{A0-=sn_p)%8cl-T^N;o4mo<_LcnH1zPf99sfV9~+d((mQG0 zhbgIFB!Jjn~= zphy@ikhs8mC{?x`2j=IH;B&nCAl*9qFF|yzCeEw3uQq7V1@HhcK_Vmh+Wd&*YK0w7 zT^W9j@=Ik#MnQ&VATkY*=q~@0g4dDsnbPHLlj?- z&%{*RKxxqR$}^?iM@&ex2t#cshcVv6cnj)1y0?ZH)a-38pgSBe6Vq-4=*1mHQ$!Cl zacAe2@ijvop2EI|BN3acX?UJQBKe-es*)tGu*qtz7m0|jP{-bgFOSN#SLR;Vn{q=5NF+UI|b;^Q=kWzWQwAHqBAu z>Lw=;ZFeO6X6e-4)MqP=K1fZBRmsm6P;u)u?S2SnKH41413dZnba3h?<`OGQCWi#=qt@2ec52C1D6c(6t-SuYBjm-PcruS#hK zo3fOUcDz2EKO0?0mz`o|&)5vf16DMj@zJ_d7@rpGlR^AE$=YEF(ljKvP!&aK)ScTi z!RlR{6E~2PgQ24y;HUcele=;e6_rT*$>^5D$CxG2of=nhdq%lb`Lx=b6G^4wDY`?R zvjfz6uin~}U}5UFou;}fqTQ(oX)eUy|XWutc9vsPEQflOdR66p6s z4KGKprGZtGxUF>b7&b||%;z%Nl-KdT6#qzOq^qp-l}E@jL``Uu>&@oStX=lc{nRs6 z8oPK^FWGZ3*Ysm+yPPlD{(YaYE(3B=X;Q-zes9?etDVANTTcUjJ`Mj5z1R ff$<;T8S;d&oOt-+lRoF?09gUw1o;d6cBcIWZ6&c5 literal 0 HcmV?d00001 diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 531168cc0..7f70940b4 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -29,6 +29,9 @@ #include "UI/Screens/ErrorScreen.h" #include "UI/Screens/TitleScreen.h" #include "UI/Screens/InventoryScreen.h" +#ifdef ENABLE_JAVA_GUIS +#include "UI/Screens/CreativeInventoryScreen.h" +#endif #include "UI/Screens/InBedChatScreen.h" #include "UI/Screens/AchievementPopup.h" #include "Input/Input.h" @@ -3385,7 +3388,10 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) std::shared_ptr player = std::dynamic_pointer_cast( Minecraft::GetInstance()->player ); ui.PlayUISFX(eSFX_Press); #ifdef ENABLE_JAVA_GUIS - setScreen(new InventoryScreen(player)); + if(gameMode->hasInfiniteItems()) + setScreen(new CreativeInventoryScreen(player)); + else + setScreen(new InventoryScreen(player)); #else app.LoadInventoryMenu(iPad,player); #endif diff --git a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h index 4320e3a17..1a0ab14d1 100644 --- a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h +++ b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h @@ -4,9 +4,12 @@ // 4J Stu - This class is for code that is common between XUI and Iggy class SimpleContainer; +class CreativeInventoryScreen; class IUIScene_CreativeMenu : public virtual IUIScene_AbstractContainerMenu { + friend class CreativeInventoryScreen; + public: // 4J Stu - These map directly to the tabs seenon the screen enum ECreativeInventoryTabs diff --git a/Minecraft.Client/Textures/Textures.cpp b/Minecraft.Client/Textures/Textures.cpp index d7dbef35f..cb633ddba 100644 --- a/Minecraft.Client/Textures/Textures.cpp +++ b/Minecraft.Client/Textures/Textures.cpp @@ -47,6 +47,10 @@ const wchar_t *Textures::preLoaded[TN_COUNT] = L"gui/container", L"gui/crafting", L"gui/furnace", + L"gui/creative_inventory/tabs", + L"gui/creative_inventory/tab_items", + L"gui/creative_inventory/tab_inventory", + L"gui/creative_inventory/tab_item_search", L"title/mclogo", #endif L"gui/icons", diff --git a/Minecraft.Client/Textures/Textures.h b/Minecraft.Client/Textures/Textures.h index 0c8994169..a31976376 100644 --- a/Minecraft.Client/Textures/Textures.h +++ b/Minecraft.Client/Textures/Textures.h @@ -35,6 +35,10 @@ typedef enum _TEXTURE_NAME TN_GUI_CONTAINER, TN_GUI_CRAFTING, TN_GUI_FURNACE, + TN_GUI_CREATIVE_TABS, + TN_GUI_CREATIVE_TAB_ITEMS, + TN_GUI_CREATIVE_TAB_INVENTORY, + TN_GUI_CREATIVE_TAB_ITEM_SEARCH, TN_TITLE_MCLOGO, #endif TN_GUI_ICONS, diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.h b/Minecraft.Client/UI/Screens/AbstractContainerScreen.h index 8086837ef..fae8d427c 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.h +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.h @@ -22,10 +22,12 @@ public: protected: virtual void renderLabels(); virtual void renderBg(float a) = 0; + // 4jcraft: promoted from private to protected so CreativeInventoryScreen can + // call findSlot() and isHovering() directly for its custom click handling. + virtual Slot *findSlot(int x, int y); + virtual bool isHovering(Slot *slot, int xm, int ym); private: virtual void renderSlot(Slot *slot); - virtual Slot *findSlot(int x, int y); - virtual bool isHovering(Slot *slot, int xm, int ym); protected: virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum); diff --git a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp new file mode 100644 index 000000000..f3da3066c --- /dev/null +++ b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp @@ -0,0 +1,527 @@ +#include "../../Platform/stdafx.h" +#include "CreativeInventoryScreen.h" +#include "../../../Minecraft.World/Headers/net.minecraft.world.entity.player.h" +#include "../../../Minecraft.World/Containers/Inventory.h" +#include "../../../Minecraft.World/Containers/SimpleContainer.h" +#include "../../../Minecraft.World/Containers/Slot.h" +#include "../../../Minecraft.World/Headers/net.minecraft.world.item.h" +#include "../../../Minecraft.World/Headers/net.minecraft.locale.h" +#include "../../Minecraft.h" +#include "../../Textures/Textures.h" +#include "../../Rendering/EntityRenderers/ItemRenderer.h" +#include "../../Rendering/Lighting.h" +#include "../../../Minecraft.World/Containers/InventoryMenu.h" +#include +#include + +// Static member initialization +int CreativeInventoryScreen::selectedTabIndex = IUIScene_CreativeMenu::eCreativeInventoryTab_BuildingBlocks; +std::shared_ptr CreativeInventoryScreen::basicInventory = std::make_shared(0, ITEMS_PER_PAGE); + +// ContainerCreative implementation +CreativeInventoryScreen::ContainerCreative::ContainerCreative(std::shared_ptr player) : AbstractContainerMenu() +{ + std::shared_ptr inventoryplayer = player->inventory; + + // Add creative inventory slots (5 rows x 9 columns = 45 slots) + for (int i = 0; i < ROWS; ++i) + { + for (int j = 0; j < COLUMNS; ++j) + { + addSlot(new Slot(basicInventory, i * COLUMNS + j, 9 + j * 18, 18 + i * 18)); + } + } + + // Add hotbar slots (9 slots at bottom) + for (int k = 0; k < 9; ++k) + { + addSlot(new Slot(inventoryplayer, k, 9 + k * 18, 112)); + } + + scrollTo(0.0f); +} + +bool CreativeInventoryScreen::ContainerCreative::stillValid(std::shared_ptr player) +{ + return true; +} + +std::shared_ptr CreativeInventoryScreen::ContainerCreative::clicked(int slotIndex, int buttonNum, int clickType, std::shared_ptr player) +{ + std::shared_ptr inventory = player->inventory; + std::shared_ptr carried = inventory->getCarried(); + + // Handle clicks outside the GUI + if (slotIndex == CLICKED_OUTSIDE) + { + // Drop the carried item + if (carried != NULL) + { + if (buttonNum == 0) + { + player->drop(carried, true); + inventory->setCarried(std::shared_ptr()); + } + else if (buttonNum == 1) + { + std::shared_ptr single = carried->copy(); + single->count = 1; + player->drop(single, true); + carried->count--; + if (carried->count <= 0) + { + inventory->setCarried(std::shared_ptr()); + } + } + } + return std::shared_ptr(); + } + + // Validate slot index + if (slotIndex < 0 || slotIndex >= (int)slots->size()) + { + return std::shared_ptr(); + } + + Slot* slot = slots->at(slotIndex); + + // Handle creative inventory slots (0-44) + if (slotIndex >= 0 && slotIndex < ITEMS_PER_PAGE) + { + std::shared_ptr slotItem = slot->getItem(); + + // Handle SWAP (number key) - copy item to hotbar + if (clickType == CLICK_SWAP) + { + if (slotItem != NULL && buttonNum >= 0 && buttonNum < 9) + { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setItem(buttonNum, copy); + } + return std::shared_ptr(); + } + + // Handle CLONE (middle click) + if (clickType == CLICK_CLONE) + { + if (slotItem != NULL) + { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setCarried(copy); + } + return std::shared_ptr(); + } + + // Handle normal clicks + if (slotItem != NULL) + { + if (buttonNum == 0) // Left click + { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setCarried(copy); + } + else if (buttonNum == 1) // Right click + { + std::shared_ptr copy = slotItem->copy(); + copy->count = 1; + inventory->setCarried(copy); + } + } + else if (carried != NULL) + { + // Clicking on empty creative slot with item - clear the carried item + inventory->setCarried(std::shared_ptr()); + } + + return std::shared_ptr(); + } + + // For hotbar slots (45-53), use normal container behavior + return AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player); +} + +void CreativeInventoryScreen::ContainerCreative::scrollTo(float pos) +{ + int i = (itemList.size() + COLUMNS - 1) / COLUMNS - ROWS; + int j = (int)((double)(pos * (float)i) + 0.5); + + if (j < 0) + { + j = 0; + } + + for (int k = 0; k < ROWS; ++k) + { + for (int l = 0; l < COLUMNS; ++l) + { + int i1 = l + (k + j) * COLUMNS; + + if (i1 >= 0 && i1 < (int)itemList.size()) + { + basicInventory->setItem(l + k * COLUMNS, itemList[i1]); + } + else + { + basicInventory->setItem(l + k * COLUMNS, std::shared_ptr()); + } + } + } +} + +bool CreativeInventoryScreen::ContainerCreative::canScroll() +{ + return itemList.size() > ITEMS_PER_PAGE; +} + +CreativeInventoryScreen::CreativeInventoryScreen(std::shared_ptr player) + : AbstractContainerScreen(new ContainerCreative(player)) +{ + this->player = player; + player->containerMenu = menu; + + currentScroll = 0.0f; + isScrolling = false; + wasClicking = false; + isLeftMouseDown = false; + + imageHeight = 136; + imageWidth = 195; +} + +void CreativeInventoryScreen::removed() +{ + AbstractContainerScreen::removed(); +} + +void CreativeInventoryScreen::init() +{ + buttons.clear(); + + int i = selectedTabIndex; + selectedTabIndex = -1; + setCurrentCreativeTab(i); +} + +void CreativeInventoryScreen::updateEvents() +{ +#ifdef ENABLE_JAVA_GUIS + // Handle mouse wheel scrolling. + // We use ButtonDown with the scroll actions rather than GetScrollDelta() because + // both share s_scrollTicksForButtonPressed; whichever is called first in a tick + // zeroes it, so GetScrollDelta() would return 0 if hotbar scroll ran first. + // ButtonDown/ScrollSnap() snapshots once per tick so all callers see the same value. + if (needsScrollBars()) + { + ContainerCreative* container = (ContainerCreative*)menu; + int totalRows = ((int)container->itemList.size() + COLUMNS - 1) / COLUMNS; + int scrollableRows = totalRows - ROWS; + if (scrollableRows > 0) + { + float step = 1.0f / (float)scrollableRows; + if (InputManager.ButtonDown(0, MINECRAFT_ACTION_LEFT_SCROLL)) + { + currentScroll -= step; + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + container->scrollTo(currentScroll); + } + else if (InputManager.ButtonDown(0, MINECRAFT_ACTION_RIGHT_SCROLL)) + { + currentScroll += step; + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + container->scrollTo(currentScroll); + } + } + } +#endif + Screen::updateEvents(); +} + +void CreativeInventoryScreen::containerTick() +{ +} + +void CreativeInventoryScreen::tick() +{ + Screen::tick(); +} + +void CreativeInventoryScreen::keyPressed(wchar_t eventCharacter, int eventKey) +{ + AbstractContainerScreen::keyPressed(eventCharacter, eventKey); +} + +void CreativeInventoryScreen::mouseClicked(int x, int y, int buttonNum) +{ + if (buttonNum == 0) isLeftMouseDown = true; + + Screen::mouseClicked(x, y, buttonNum); + + if (buttonNum == 0 || buttonNum == 1) + { + int i = x - (width - imageWidth) / 2; + int j = y - (height - imageHeight) / 2; + + // Check for tab clicks first; let mouseReleased handle the actual tab switch + for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) + { + if (isMouseOverTab(tab, i, j)) + { + return; + } + } + + // Determine which slot (if any) was clicked + Slot *slot = findSlot(x, y); + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + bool clickedOutside = (x < xo || y < yo || x >= xo + imageWidth || y >= yo + imageHeight); + + int slotId = -1; + if (slot != NULL) slotId = slot->index; + if (clickedOutside) slotId = AbstractContainerMenu::CLICKED_OUTSIDE; + + if (slotId == -1) return; + + bool quickKey = slotId != AbstractContainerMenu::CLICKED_OUTSIDE && + (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); + int clickType = quickKey ? AbstractContainerMenu::CLICK_QUICK_MOVE : AbstractContainerMenu::CLICK_PICKUP; + + // 4jcraft: bypass AbstractContainerScreen::mouseClicked / handleInventoryMouseClick + // here intentionally. The normal path sends a ContainerClickPacket to the server, + // where player->containerMenu is still the InventoryMenu (45 slots). Creative slot + // indices 0-44 are valid in ContainerCreative but not in InventoryMenu, and hotbar + // indices 45-53 exceed InventoryMenu's slot count entirely, causing an out-of-range + // crash in AbstractContainerMenu::clicked on the server side. + // Instead we apply the click locally and sync hotbar changes via SetCreativeModeSlotPacket. + menu->clicked(slotId, buttonNum, clickType, minecraft->player); + + // 4jcraft: sync hotbar slot changes to the server using SetCreativeModeSlotPacket. + // The packet handler (PlayerConnection::handleSetCreativeModeSlot) validates slots + // against InventoryMenu coordinates where the hotbar starts at USE_ROW_SLOT_START (36), + // so we must offset the local hotbar index (0-8) accordingly. + if (slotId >= ITEMS_PER_PAGE && slotId < ITEMS_PER_PAGE + 9) + { + int hotbarSlot = slotId - ITEMS_PER_PAGE; + std::shared_ptr hotbarItem = minecraft->player->inventory->getItem(hotbarSlot); + minecraft->gameMode->handleCreativeModeItemAdd(hotbarItem, hotbarSlot + InventoryMenu::USE_ROW_SLOT_START); + } + } +} + +void CreativeInventoryScreen::mouseReleased(int x, int y, int buttonNum) +{ + if (buttonNum == 0) isLeftMouseDown = false; + + if (buttonNum == 0) + { + int i = x - (width - imageWidth) / 2; + int j = y - (height - imageHeight) / 2; + + // Check for tab clicks + for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) + { + if (isMouseOverTab(tab, i, j)) + { + setCurrentCreativeTab(tab); + return; + } + } + } + + AbstractContainerScreen::mouseReleased(x, y, buttonNum); +} + +void CreativeInventoryScreen::render(int xm, int ym, float a) +{ + // Java: drawDefaultBackground() + renderBackground(); + + // Handle scrollbar dragging + bool mouseDown = isLeftMouseDown; + int i = (width - imageWidth) / 2; + int j = (height - imageHeight) / 2; + int k = i + 175; + int l = j + 18; + int i1 = k + 14; + int j1 = l + 112; + + if (!wasClicking && mouseDown && xm >= k && ym >= l && xm < i1 && ym < j1) + { + isScrolling = needsScrollBars(); + } + + if (!mouseDown) + { + isScrolling = false; + } + + wasClicking = mouseDown; + + if (isScrolling) + { + currentScroll = ((float)(ym - l) - 7.5f) / ((float)(j1 - l) - 15.0f); + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + ((ContainerCreative*)menu)->scrollTo(currentScroll); + } + + AbstractContainerScreen::render(xm, ym, a); +} + +void CreativeInventoryScreen::renderLabels() +{ +#ifdef ENABLE_JAVA_GUIS + if (IUIScene_CreativeMenu::specs && selectedTabIndex >= 0 && selectedTabIndex < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) + { + IUIScene_CreativeMenu::TabSpec* spec = IUIScene_CreativeMenu::specs[selectedTabIndex]; + if (spec) + { + std::wstring tabName = app.GetString(spec->m_descriptionId); + font->draw(tabName, 8, 6, 0x404040); + } + } +#endif +} + +void CreativeInventoryScreen::renderBg(float a) +{ + int x = (width - imageWidth) / 2; + int y = (height - imageHeight) / 2; + +#ifdef ENABLE_JAVA_GUIS + // Render all non-selected tabs first + for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) + { + if (tab != selectedTabIndex) + { + drawTab(tab); + } + } + + // Load and render main creative inventory background + int tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TAB_ITEMS); + glColor4f(1, 1, 1, 1); + minecraft->textures->bind(tex); + blit(x, y, 0, 0, imageWidth, imageHeight); + + // Render scrollbar + tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); + minecraft->textures->bind(tex); + + int scrollX = x + 175; + int scrollY = y + 18; + int scrollHeight = 112; + + if (needsScrollBars()) + { + int scrollPos = (int)((float)(scrollHeight - 17) * currentScroll); + blit(scrollX, scrollY + scrollPos, 232, 0, 12, 15); + } + else + { + blit(scrollX, scrollY + (scrollHeight - 17) / 2, 244, 0, 12, 15); + } + + // Render selected tab last (on top) + drawTab(selectedTabIndex); +#endif +} + +void CreativeInventoryScreen::setCurrentCreativeTab(int tab) +{ + if (tab < 0 || tab >= IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) + return; + + int oldTab = selectedTabIndex; + selectedTabIndex = tab; + + ContainerCreative* container = (ContainerCreative*)menu; + container->itemList.clear(); + + // Populate itemList from the tab's category groups + if (IUIScene_CreativeMenu::specs && IUIScene_CreativeMenu::specs[tab]) + { + IUIScene_CreativeMenu::TabSpec* spec = IUIScene_CreativeMenu::specs[tab]; + + // Add items from static groups + for (int i = 0; i < spec->m_staticGroupsCount; ++i) + { + int groupIdx = spec->m_staticGroupsA[i]; + if (groupIdx >= 0 && groupIdx < IUIScene_CreativeMenu::eCreativeInventoryGroupsCount) + { + auto& group = IUIScene_CreativeMenu::categoryGroups[groupIdx]; + for (auto& item : group) + { + container->itemList.push_back(item); + } + } + } + } + + currentScroll = 0.0f; + container->scrollTo(0.0f); +} + +void CreativeInventoryScreen::selectTab(int tab) +{ + setCurrentCreativeTab(tab); +} + +bool CreativeInventoryScreen::needsScrollBars() +{ + return ((ContainerCreative*)menu)->canScroll(); +} + +bool CreativeInventoryScreen::isMouseOverTab(int tab, int mouseX, int mouseY) +{ + int i = tab; + int j = 28 * i; + int k = 0; + + if (i > 0) + { + j += i; + } + + // Tabs are in the top row + k = k - 32; + + return mouseX >= j && mouseX <= j + 28 && mouseY >= k && mouseY <= k + 32; +} + +void CreativeInventoryScreen::drawTab(int tab) +{ +#ifdef ENABLE_JAVA_GUIS + bool isSelected = (tab == selectedTabIndex); + int i = tab; + int j = i * 28; + int k = 0; + int l = (width - imageWidth) / 2 + 28 * i; + int i1 = (height - imageHeight) / 2; + int j1 = 32; + + if (isSelected) + { + k += 32; + } + + if (i > 0) + { + l += i; + } + + // Tabs are in the top row + i1 = i1 - 28; + + // Render tab background + int tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); + minecraft->textures->bind(tex); + glColor4f(1, 1, 1, 1); + blit(l, i1, j, k, 28, 32); + + // TODO: Render tab icon (would need item icons) +#endif +} diff --git a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h new file mode 100644 index 000000000..4ce1659f4 --- /dev/null +++ b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h @@ -0,0 +1,71 @@ +#pragma once +#include "AbstractContainerScreen.h" +#include "../../../Minecraft.World/Containers/AbstractContainerMenu.h" +#include "../../Platform/Common/UI/IUIScene_CreativeMenu.h" +#include "../../Player/MultiPlayerLocalPlayer.h" + +class Player; +class SimpleContainer; +class Inventory; +class Slot; + +class CreativeInventoryScreen : public AbstractContainerScreen +{ +private: + static constexpr int ROWS = 5; + static constexpr int COLUMNS = 9; + static constexpr int ITEMS_PER_PAGE = ROWS * COLUMNS; // 45 items (9x5 grid) + + // Currently selected creative tab index + static int selectedTabIndex; + + // Temporary inventory for creative mode items + static std::shared_ptr basicInventory; + + // Amount scrolled in Creative mode inventory (0 = top, 1 = bottom) + float currentScroll; + + bool isScrolling; + + // True if the left mouse button is currently being held + bool isLeftMouseDown; + + // True if the left mouse button was held down last time render was called + bool wasClicking; + + std::shared_ptr player; + +public: + class ContainerCreative : public AbstractContainerMenu + { + public: + std::vector> itemList; + + ContainerCreative(std::shared_ptr player); + virtual bool stillValid(std::shared_ptr player); + virtual std::shared_ptr clicked(int slotIndex, int buttonNum, int clickType, std::shared_ptr player); + void scrollTo(float pos); + bool canScroll(); + }; + +public: + CreativeInventoryScreen(std::shared_ptr player); + virtual void removed(); + virtual void init(); + virtual void containerTick(); + virtual void tick(); + virtual void updateEvents(); + virtual void keyPressed(wchar_t eventCharacter, int eventKey); + virtual void mouseClicked(int x, int y, int buttonNum); + virtual void mouseReleased(int x, int y, int buttonNum); + virtual void render(int xm, int ym, float a); +protected: + virtual void renderLabels(); + virtual void renderBg(float a); +private: + void setCurrentCreativeTab(int tab); + void selectTab(int tab); + bool needsScrollBars(); + bool isMouseOverTab(int tab, int mouseX, int mouseY); + void drawTab(int tab); +}; From e4428a983a281720dd3cf39e2594dbfe6bde626e Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Fri, 13 Mar 2026 16:52:34 +0300 Subject: [PATCH 15/29] feat: backport more advanced world creation screen from 1.3.2 Main reference used was MCP 7.1 This allows players to toggle: Gamemodes Structure generation Flat/normal world generation Cheats (needs chat fully implemented to work however) --- .../UI/Screens/CreateWorldScreen.cpp | 147 +++++++++++++++--- .../UI/Screens/CreateWorldScreen.h | 19 +++ 2 files changed, 145 insertions(+), 21 deletions(-) diff --git a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp index daf4cd29d..cb900e228 100644 --- a/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp +++ b/Minecraft.Client/UI/Screens/CreateWorldScreen.cpp @@ -16,13 +16,19 @@ CreateWorldScreen::CreateWorldScreen(Screen *lastScreen) { done = false; // 4J added + moreOptions = false; + gameMode = L"survival"; + generateStructures = true; + bonusChest = false; + cheatsEnabled = false; + flatWorld = false; this->lastScreen = lastScreen; } void CreateWorldScreen::tick() { nameEdit->tick(); - seedEdit->tick(); + if (moreOptions) seedEdit->tick(); // 4J - debug code - to be removed static int count = 0; @@ -35,18 +41,55 @@ void CreateWorldScreen::init() Keyboard::enableRepeatEvents(true); buttons.clear(); - buttons.push_back(new Button(0, width / 2 - 100, height / 4 + 24 * 4 + 12, language->getElement(L"selectWorld.create"))); - buttons.push_back(new Button(1, width / 2 - 100, height / 4 + 24 * 5 + 12, language->getElement(L"gui.cancel"))); + buttons.push_back(new Button(0, width / 2 - 155, height - 28, 150, 20, language->getElement(L"selectWorld.create"))); + buttons.push_back(new Button(1, width / 2 + 5, height - 28, 150, 20, language->getElement(L"gui.cancel"))); nameEdit = new EditBox(this, font, width / 2 - 100, 60, 200, 20, language->getElement(L"testWorld")); // 4J - test - should be L"selectWorld.newWorld" nameEdit->inFocus = true; nameEdit->setMaxLength(32); - seedEdit = new EditBox(this, font, width / 2 - 100, 116, 200, 20, L""); + seedEdit = new EditBox(this, font, width / 2 - 100, 60, 200, 20, L""); + buttons.push_back(gameModeButton = new Button(2, width / 2 - 75, 100, 150, 20, language->getElement(L"selectWorld.gameMode"))); + buttons.push_back(moreWorldOptionsButton = new Button(3, width / 2 - 75, 172, 150, 20, language->getElement(L"selectWorld.moreWorldOptions"))); + buttons.push_back(generateStructuresButton = new Button(4, width / 2 - 155, 100, 150, 20, language->getElement(L"selectWorld.mapFeatures"))); + generateStructuresButton->visible = false; + generateStructuresButton->active = false; + buttons.push_back(bonusChestButton = new Button(7, width / 2 + 5, 136, 150, 20, language->getElement(L"selectWorld.bonusItems"))); + bonusChestButton->visible = false; + bonusChestButton->active = false; + buttons.push_back(worldTypeButton = new Button(5, width / 2 + 5, 100, 150, 20, language->getElement(L"selectWorld.mapType"))); + worldTypeButton->visible = false; + worldTypeButton->active = false; + buttons.push_back(cheatsEnabledButton = new Button(6, width / 2 - 155, 136, 150, 20, language->getElement(L"selectWorld.allowCommands"))); + cheatsEnabledButton->visible = false; + cheatsEnabledButton->active = false; + + updateStrings(); updateResultFolder(); } +// 4jcraft: referenced from func_73914_h in MCP 7.1 fr those wondering +void CreateWorldScreen::updateStrings() +{ + Language *language = Language::getInstance(); + + gameModeButton->msg = language->getElement(L"selectWorld.gameMode") + L" " + language->getElement(L"selectWorld.gameMode." + gameMode); + + std::wstring line1Key = L"selectWorld.gameMode." + gameMode + L".line1"; + std::wstring line2Key = L"selectWorld.gameMode." + gameMode + L".line2"; + gameModeDescriptionLine1 = language->getElement(line1Key); + gameModeDescriptionLine2 = language->getElement(line2Key); + + generateStructuresButton->msg = language->getElement(L"selectWorld.mapFeatures") + L" " + (generateStructures ? language->getElement(L"options.on") : language->getElement(L"options.off")); + + bonusChestButton->msg = language->getElement(L"selectWorld.bonusItems") + L" " + (bonusChest ? language->getElement(L"options.on") : language->getElement(L"options.off")); + + worldTypeButton->msg = language->getElement(L"selectWorld.mapType") + L" " + (flatWorld ? language->getElement(L"selectWorld.mapType.flat") : language->getElement(L"selectWorld.mapType.normal")); + + cheatsEnabledButton->msg = language->getElement(L"selectWorld.allowCommands") + L" " + (cheatsEnabled ? language->getElement(L"options.on") : language->getElement(L"options.off")); +} + void CreateWorldScreen::updateResultFolder() { resultFolder = trimString(nameEdit->getValue()); @@ -104,9 +147,9 @@ void CreateWorldScreen::buttonClicked(Button *button) // these r just the defaults from the createworldmenu UIscene // i had higher ambitions for what id do with these but its not worth it for a temp ui moreOptionsParams->bGenerateOptions = TRUE; - moreOptionsParams->bStructures = TRUE; - moreOptionsParams->bFlatWorld = FALSE; - moreOptionsParams->bBonusChest = FALSE; + moreOptionsParams->bStructures = generateStructures; + moreOptionsParams->bFlatWorld = flatWorld; + moreOptionsParams->bBonusChest = bonusChest; moreOptionsParams->bPVP = TRUE; moreOptionsParams->bTrust = TRUE; moreOptionsParams->bFireSpreads = TRUE; @@ -116,14 +159,13 @@ void CreateWorldScreen::buttonClicked(Button *button) moreOptionsParams->bInviteOnly = FALSE; moreOptionsParams->bAllowFriendsOfFriends = FALSE; moreOptionsParams->bOnlineSettingChangedBySystem = FALSE; + moreOptionsParams->bCheatsEnabled = cheatsEnabled; moreOptionsParams->iPad = 0; moreOptionsParams->worldName = nameEdit->getValue(); moreOptionsParams->seed = seedEdit->getValue(); moreOptionsParams->dwTexturePack = 0; - - bool bGameModeSurvival = true; std::wstring worldName = nameEdit->getValue(); if (worldName.empty()) @@ -191,7 +233,7 @@ void CreateWorldScreen::buttonClicked(Button *button) app.SetGameHostOption(eGameHostOption_FriendsOfFriends, moreOptionsParams->bAllowFriendsOfFriends); app.SetGameHostOption(eGameHostOption_Gamertags, 1); app.SetGameHostOption(eGameHostOption_BedrockFog, 0); - app.SetGameHostOption(eGameHostOption_GameType, bGameModeSurvival ? GameType::SURVIVAL->getId() : GameType::CREATIVE->getId()); // TODO: gamemode switch + app.SetGameHostOption(eGameHostOption_GameType, (gameMode == L"survival") ? GameType::SURVIVAL->getId() : GameType::CREATIVE->getId()); app.SetGameHostOption(eGameHostOption_LevelType, moreOptionsParams->bFlatWorld); app.SetGameHostOption(eGameHostOption_Structures, moreOptionsParams->bStructures); app.SetGameHostOption(eGameHostOption_BonusChest, moreOptionsParams->bBonusChest); @@ -202,6 +244,7 @@ void CreateWorldScreen::buttonClicked(Button *button) app.SetGameHostOption(eGameHostOption_HostCanFly, moreOptionsParams->bHostPrivileges); app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, moreOptionsParams->bHostPrivileges); app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, moreOptionsParams->bHostPrivileges); + app.SetGameHostOption(eGameHostOption_CheatsEnabled, moreOptionsParams->bHostPrivileges); param->settings = app.GetGameHostOption(eGameHostOption_All); param->xzSize = LEVEL_MAX_WIDTH; @@ -232,12 +275,61 @@ void CreateWorldScreen::buttonClicked(Button *button) minecraft->setScreen(NULL); #endif } - + else if (button->id == 2) + { + if (gameMode == L"survival") gameMode = L"creative"; + else gameMode = L"survival"; + updateStrings(); + } + else if (button->id == 3) + { + moreOptions = !moreOptions; + gameModeButton->visible = !moreOptions; + gameModeButton->active = !moreOptions; + generateStructuresButton->visible = moreOptions; + generateStructuresButton->active = moreOptions; + bonusChestButton->visible = moreOptions; + bonusChestButton->active = moreOptions; + worldTypeButton->visible = moreOptions; + worldTypeButton->active = moreOptions; + cheatsEnabledButton->visible = moreOptions; + cheatsEnabledButton->active = moreOptions; + + Language *language = Language::getInstance(); + if (moreOptions) + { + moreWorldOptionsButton->msg = language->getElement(L"gui.done"); + } + else + { + moreWorldOptionsButton->msg = language->getElement(L"selectWorld.moreWorldOptions"); + } + } + else if (button->id == 4) + { + generateStructures = !generateStructures; + updateStrings(); + } + else if (button->id == 7) + { + bonusChest = !bonusChest; + updateStrings(); + } + else if (button->id == 5) + { + flatWorld = !flatWorld; + updateStrings(); + } + else if (button->id == 6) + { + cheatsEnabled = !cheatsEnabled; + updateStrings(); + } } void CreateWorldScreen::keyPressed(wchar_t ch, int eventKey) { - if (nameEdit->inFocus) nameEdit->keyPressed(ch, eventKey); + if (nameEdit->inFocus && !moreOptions) nameEdit->keyPressed(ch, eventKey); else seedEdit->keyPressed(ch, eventKey); if (ch == 13) @@ -253,8 +345,8 @@ void CreateWorldScreen::mouseClicked(int x, int y, int buttonNum) { Screen::mouseClicked(x, y, buttonNum); - nameEdit->mouseClicked(x, y, buttonNum); - seedEdit->mouseClicked(x, y, buttonNum); + if (!moreOptions) nameEdit->mouseClicked(x, y, buttonNum); + else seedEdit->mouseClicked(x, y, buttonNum); } void CreateWorldScreen::render(int xm, int ym, float a) @@ -264,15 +356,26 @@ void CreateWorldScreen::render(int xm, int ym, float a) // fill(0, 0, width, height, 0x40000000); renderBackground(); - drawCenteredString(font, language->getElement(L"selectWorld.create"), width / 2, height / 4 - 60 + 20, 0xffffff); - drawString(font, language->getElement(L"selectWorld.enterName"), width / 2 - 100, 47, 0xa0a0a0); - drawString(font, language->getElement(L"selectWorld.resultFolder") + L" " + resultFolder, width / 2 - 100, 85, 0xa0a0a0); + drawCenteredString(font, language->getElement(L"selectWorld.create"), width / 2, 20, 0xffffff); + if (!moreOptions) + { + drawString(font, language->getElement(L"selectWorld.enterName"), width / 2 - 100, 47, 0xa0a0a0); + drawString(font, language->getElement(L"selectWorld.resultFolder") + L" " + resultFolder, width / 2 - 100, 85, 0xa0a0a0); - drawString(font, language->getElement(L"selectWorld.enterSeed"), width / 2 - 100, 104, 0xa0a0a0); - drawString(font, language->getElement(L"selectWorld.seedInfo"), width / 2 - 100, 140, 0xa0a0a0); + nameEdit->render(); - nameEdit->render(); - seedEdit->render(); + drawString(font, gameModeDescriptionLine1, width / 2 - 100, 122, 0xa0a0a0); + drawString(font, gameModeDescriptionLine2, width / 2 - 100, 134, 0xa0a0a0); + } + else + { + drawString(font, language->getElement(L"selectWorld.enterSeed"), width / 2 - 100, 47, 0xa0a0a0); + drawString(font, language->getElement(L"selectWorld.seedInfo"), width / 2 - 100, 85, 0xa0a0a0); + drawString(font, language->getElement(L"selectWorld.mapFeatures.info"), width / 2 - 150, 122, 0xa0a0a0); + drawString(font, language->getElement(L"selectWorld.allowCommands.info"), width / 2 - 150, 157, 0xa0a0a0); + + seedEdit->render(); + } Screen::render(xm, ym, a); @@ -280,6 +383,8 @@ void CreateWorldScreen::render(int xm, int ym, float a) void CreateWorldScreen::tabPressed() { + if (!moreOptions) return; + if (nameEdit->inFocus) { nameEdit->focus(false); diff --git a/Minecraft.Client/UI/Screens/CreateWorldScreen.h b/Minecraft.Client/UI/Screens/CreateWorldScreen.h index d2d7bcea8..321f9221c 100644 --- a/Minecraft.Client/UI/Screens/CreateWorldScreen.h +++ b/Minecraft.Client/UI/Screens/CreateWorldScreen.h @@ -13,12 +13,30 @@ private: std::wstring resultFolder; bool done; + bool moreOptions; + std::wstring gameMode; + bool generateStructures; + bool bonusChest; + bool cheatsEnabled; + bool flatWorld; + + Button *gameModeButton; + Button *moreWorldOptionsButton; + Button *generateStructuresButton; + Button *bonusChestButton; + Button *worldTypeButton; + Button *cheatsEnabledButton; + + std::wstring gameModeDescriptionLine1; + std::wstring gameModeDescriptionLine2; + std::wstring seed; public: CreateWorldScreen(Screen *lastScreen); virtual void tick(); virtual void init(); private: void updateResultFolder(); + void updateStrings(); public: static std::wstring findAvailableFolderName(LevelStorageSource *levelSource, const std::wstring& folder); virtual void removed(); @@ -56,6 +74,7 @@ private: bool bInviteOnly; bool bAllowFriendsOfFriends; bool bOnlineSettingChangedBySystem; + bool bCheatsEnabled; int dwTexturePack; int iPad; std::wstring worldName; From 04b76893ca1fdd08aabb483e262c5560c71a9901 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Fri, 13 Mar 2026 20:53:41 +0300 Subject: [PATCH 16/29] feat: re-enable boss health bar --- Minecraft.Client/UI/Gui.cpp | 70 +++++++++++++++++++------------------ Minecraft.Client/UI/Gui.h | 2 +- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/Minecraft.Client/UI/Gui.cpp b/Minecraft.Client/UI/Gui.cpp index 83893d4a9..6dad298c4 100644 --- a/Minecraft.Client/UI/Gui.cpp +++ b/Minecraft.Client/UI/Gui.cpp @@ -365,7 +365,9 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // if (false) //(true) // { -// renderBossHealth(); +#ifdef ENABLE_JAVA_GUIS + renderBossHealth(); +#endif // } ///////////////////////////////////////////////////////////////////////////////////// @@ -1028,39 +1030,39 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) } // Moved to the xui base scene -// void Gui::renderBossHealth(void) -// { -// if (EnderDragonRenderer::bossInstance == NULL) return; -// -// std::shared_ptr boss = EnderDragonRenderer::bossInstance; -// EnderDragonRenderer::bossInstance = NULL; -// -// Minecraft *pMinecraft=Minecraft::GetInstance(); -// -// Font *font = pMinecraft->font; -// -// ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); -// int screenWidth = ssc.getWidth(); -// -// int w = 182; -// int xLeft = screenWidth / 2 - w / 2; -// -// int progress = (int) (boss->getSynchedHealth() / (float) boss->getMaxHealth() * (float) (w + 1)); -// -// int yo = 12; -// blit(xLeft, yo, 0, 74, w, 5); -// blit(xLeft, yo, 0, 74, w, 5); -// if (progress > 0) -// { -// blit(xLeft, yo, 0, 79, progress, 5); -// } -// -// std::wstring msg = L"Boss health - NON LOCALISED"; -// font->drawShadow(msg, screenWidth / 2 - font->width(msg) / 2, yo - 10, 0xff00ff); -// glColor4f(1, 1, 1, 1); -// glBindTexture(GL_TEXTURE_2D, pMinecraft->textures->loadTexture(TN_GUI_ICONS) );//"/gui/icons.png")); -// -// } +void Gui::renderBossHealth(void) +{ + if (EnderDragonRenderer::bossInstance == NULL) return; + + std::shared_ptr boss = EnderDragonRenderer::bossInstance; + EnderDragonRenderer::bossInstance = NULL; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + Font *font = pMinecraft->font; + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + int screenWidth = ssc.getWidth(); + + int w = 182; + int xLeft = screenWidth / 2 - w / 2; + + int progress = (int) (boss->getSynchedHealth() / (float) boss->getMaxHealth() * (float) (w + 1)); + + int yo = 12; + blit(xLeft, yo, 0, 74, w, 5); + blit(xLeft, yo, 0, 74, w, 5); + if (progress > 0) + { + blit(xLeft, yo, 0, 79, progress, 5); + } + + std::wstring msg = L"Boss health"/*L"Boss health - NON LOCALISED"*/; + font->drawShadow(msg, screenWidth / 2 - font->width(msg) / 2, yo - 10, 0xff00ff); + glColor4f(1, 1, 1, 1); + glBindTexture(GL_TEXTURE_2D, pMinecraft->textures->loadTexture(TN_GUI_ICONS) );//"/gui/icons.png")); + +} void Gui::renderPumpkin(int w, int h) { diff --git a/Minecraft.Client/UI/Gui.h b/Minecraft.Client/UI/Gui.h index 725a3b4c6..0e7df22c9 100644 --- a/Minecraft.Client/UI/Gui.h +++ b/Minecraft.Client/UI/Gui.h @@ -43,7 +43,7 @@ public: float tbr; private: - //void renderBossHealth(void); + void renderBossHealth(void); void renderPumpkin(int w, int h); void renderVignette(float br, int w, int h); void renderTp(float br, int w, int h); From bb668d136afbbe9c1615961d394b54debbc3ce5e Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Fri, 13 Mar 2026 21:34:39 +0300 Subject: [PATCH 17/29] fix: add level null check to advanced opengl toggle --- Minecraft.Client/GameState/Options.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Minecraft.Client/GameState/Options.cpp b/Minecraft.Client/GameState/Options.cpp index 06b08d5bd..47acf2f26 100644 --- a/Minecraft.Client/GameState/Options.cpp +++ b/Minecraft.Client/GameState/Options.cpp @@ -260,7 +260,8 @@ void Options::toggle(const Options::Option *option, int dir) if (option == Option::ADVANCED_OPENGL) { advancedOpengl = !advancedOpengl; - minecraft->levelRenderer->allChanged(); + // 4jcraft: ensure level exists before applying + if(minecraft->level) minecraft->levelRenderer->allChanged(); } if (option == Option::ANAGLYPH) { From 1c5184e31680a74311f53c4cd6f8b78ec46a005b Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Fri, 13 Mar 2026 21:43:26 +0300 Subject: [PATCH 18/29] fix: add more null checks to options --- Minecraft.Client/GameState/Options.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/GameState/Options.cpp b/Minecraft.Client/GameState/Options.cpp index 47acf2f26..02d8727f4 100644 --- a/Minecraft.Client/GameState/Options.cpp +++ b/Minecraft.Client/GameState/Options.cpp @@ -279,12 +279,14 @@ void Options::toggle(const Options::Option *option, int dir) if (option == Option::GRAPHICS) { fancyGraphics = !fancyGraphics; - minecraft->levelRenderer->allChanged(); + // 4jcraft: ensure level exists before applying + if(minecraft->level) minecraft->levelRenderer->allChanged(); } if (option == Option::AMBIENT_OCCLUSION) { ambientOcclusion = !ambientOcclusion; - minecraft->levelRenderer->allChanged(); + // 4jcraft: ensure level exists before applying + if(minecraft->level) minecraft->levelRenderer->allChanged(); } // 4J-PB - don't do the file save on the xbox From 3f2e7338ccedb16a2c910b943445692aae9fd749 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Sat, 14 Mar 2026 18:00:15 +0300 Subject: [PATCH 19/29] feat: complete language class implementation yes clang-format was used --- Minecraft.Assets/Common/res/lang/en_US.lang | 984 ++++++++++++++++++++ Minecraft.World/Util/Language.cpp | 126 ++- Minecraft.World/Util/Language.h | 13 +- 3 files changed, 1089 insertions(+), 34 deletions(-) create mode 100644 Minecraft.Assets/Common/res/lang/en_US.lang diff --git a/Minecraft.Assets/Common/res/lang/en_US.lang b/Minecraft.Assets/Common/res/lang/en_US.lang new file mode 100644 index 000000000..cdce905c0 --- /dev/null +++ b/Minecraft.Assets/Common/res/lang/en_US.lang @@ -0,0 +1,984 @@ + +language.name=English +language.region=US +language.code=en_US + +gui.done=Done +gui.cancel=Cancel +gui.toMenu=Back to title screen +gui.up=Up +gui.down=Down +gui.yes=Yes +gui.no=No + +menu.singleplayer=Singleplayer +menu.multiplayer=Multiplayer +menu.mods=Texture Packs +menu.options=Options... +menu.quit=Quit Game +menu.returnToMenu=Save and Quit to Title +menu.disconnect=Disconnect +menu.returnToGame=Back to Game +menu.switchingLevel=Switching worlds +menu.generatingLevel=Generating world +menu.loadingLevel=Loading world +menu.generatingTerrain=Building terrain +menu.convertingLevel=Converting world +menu.simulating=Simulating the world for a bit +menu.respawning=Respawning +menu.shareToLan=Open to LAN + +selectWorld.title=Select World +selectWorld.empty=empty +selectWorld.world=World +selectWorld.select=Play Selected World +selectWorld.create=Create New World +selectWorld.createDemo=Play New Demo World +selectWorld.delete=Delete +selectWorld.rename=Rename +selectWorld.deleteQuestion=Are you sure you want to delete this world? +selectWorld.deleteWarning=will be lost forever! (A long time!) +selectWorld.deleteButton=Delete +selectWorld.renameButton=Rename +selectWorld.renameTitle=Rename World +selectWorld.conversion=Must be converted! +selectWorld.newWorld=New World +selectWorld.enterName=World Name +selectWorld.resultFolder=Will be saved in: +selectWorld.enterSeed=Seed for the World Generator +selectWorld.seedInfo=Leave blank for a random seed +selectWorld.cheats=Cheats + +gameMode.survival=Survival Mode +gameMode.creative=Creative Mode +gameMode.adventure=Adventure Mode +gameMode.hardcore=Hardcore Mode! +gameMode.changed=Your game mode has been changed + +selectWorld.gameMode=Game Mode: +selectWorld.gameMode.survival=Survival +selectWorld.gameMode.survival.line1=Search for resources, crafting, gain +selectWorld.gameMode.survival.line2=levels, health and hunger +selectWorld.gameMode.creative=Creative +selectWorld.gameMode.creative.line1=Unlimited resources, free flying and +selectWorld.gameMode.creative.line2=destroy blocks instantly +selectWorld.gameMode.hardcore=Hardcore +selectWorld.gameMode.hardcore.line1=Same as survival mode, locked at hardest +selectWorld.gameMode.hardcore.line2=difficulty, and one life only +selectWorld.gameMode.adventure=Adventure +selectWorld.gameMode.adventure.line1=Same as survival mode, but blocks can't +selectWorld.gameMode.adventure.line2=be added or removed +selectWorld.moreWorldOptions=More World Options... +selectWorld.mapFeatures=Generate Structures: +selectWorld.mapFeatures.info=Villages, dungeons etc +selectWorld.mapType=World Type: +selectWorld.mapType.normal=Normal +selectWorld.mapType.flat=Superflat +selectWorld.allowCommands=Allow Cheats: +selectWorld.allowCommands.info=Commands like /gamemode, /xp +selectWorld.hardcoreMode=Hardcore: +selectWorld.hardcoreMode.info=World is deleted upon death +selectWorld.bonusItems=Bonus Chest: + +generator.default=Default +generator.flat=Superflat +generator.largeBiomes=Large Biomes + +selectServer.title=Select Server +selectServer.empty=empty +selectServer.select=Join Server +selectServer.direct=Direct Connect +selectServer.edit=Edit +selectServer.delete=Delete +selectServer.add=Add server +selectServer.defaultName=Minecraft Server +selectServer.deleteQuestion=Are you sure you want to remove this server? +selectServer.deleteWarning=will be lost forever! (A long time!) +selectServer.deleteButton=Delete +selectServer.refresh=Refresh +addServer.title=Edit Server Info +addServer.enterName=Server Name +addServer.enterIp=Server Address +addServer.add=Done +lanServer.title=LAN World +lanServer.scanning=Scanning for LAN Worlds +lanServer.start=Start LAN World +lanServer.otherPlayers=Settings for Other Players + +multiplayer.title=Play Multiplayer +multiplayer.connect=Connect +multiplayer.info1=Minecraft Multiplayer is currently not finished, but there +multiplayer.info2=is some buggy early testing going on. +multiplayer.ipinfo=Enter the IP of a server to connect to it: + +multiplayer.texturePrompt.line1=This server recommends the use of a custom texture pack. +multiplayer.texturePrompt.line2=Would you like to download and install it automagically? + +multiplayer.downloadingTerrain=Downloading terrain + +multiplayer.stopSleeping=Leave Bed + +chat.link.confirm=Are you sure you want to open the following website? +chat.link.warning=Never open links from people that you don't trust! +chat.copy=Copy to Clipboard + +menu.playdemo=Play Demo World +menu.resetdemo=Reset Demo World +demo.day.1=This demo will last five game days, do your best! +demo.day.2=Day Two +demo.day.3=Day Three +demo.day.4=Day Four +demo.day.5=This is your last day! +demo.day.warning=Your time is almost up! +demo.day.6=You have passed your fifth day, use F2 to save a screenshot of your creation +demo.reminder=The demo time has expired, buy the game to continue or start a new world! +demo.remainingTime=Remaining time: %s +demo.demoExpired=Demo time's up! +demo.help.movement=Use %1$s, %2$s, %3$s, %4$s and the mouse to move around +demo.help.movementShort=Move by pressing %1$s, %2$s, %3$s, %4$s +demo.help.movementMouse=Look around using the mouse +demo.help.jump=Jump by pressing %1$s +demo.help.inventory=Use %1$s to open your inventory +demo.help.title=Minecraft Demo Mode +demo.help.fullWrapped=This demo will last 5 ingame days (about 1 hour and 40 minutes of real time). Check the achievements for hints! Have fun! +demo.help.buy=Purchase Now! +demo.help.later=Continue Playing! + +connect.connecting=Connecting to the server... +connect.authorizing=Logging in... +connect.failed=Failed to connect to the server + +disconnect.genericReason=%s +disconnect.disconnected=Disconnected by Server +disconnect.lost=Connection Lost +disconnect.kicked=Was kicked from the game +disconnect.timeout=Timed out +disconnect.closed=Connection closed +disconnect.loginFailed=Failed to login +disconnect.loginFailedInfo=Failed to login: %s +disconnect.quitting=Quitting +disconnect.endOfStream=End of stream +disconnect.overflow=Buffer overflow +disconnect.spam=Kicked for spamming + +options.off=OFF +options.on=ON +options.visible=Shown +options.hidden=Hidden +options.title=Options +options.controls=Controls... +options.video=Video Settings... +options.language=Language... +options.languageWarning=Language translations may not be 100% accurate +options.videoTitle=Video Settings +options.music=Music +options.sound=Sound +options.invertMouse=Invert Mouse +options.fov=FOV +options.fov.min=Normal +options.fov.max=Quake Pro +options.gamma=Brightness +options.gamma.min=Moody +options.gamma.max=Bright +options.sensitivity=Sensitivity +options.sensitivity.min=*yawn* +options.sensitivity.max=HYPERSPEED!!! +options.renderDistance=Render Distance +options.renderDistance.tiny=Tiny +options.renderDistance.short=Short +options.renderDistance.normal=Normal +options.renderDistance.far=Far +options.viewBobbing=View Bobbing +options.ao=Smooth Lighting +options.anaglyph=3D Anaglyph +options.framerateLimit=Performance +options.difficulty=Difficulty +options.difficulty.peaceful=Peaceful +options.difficulty.easy=Easy +options.difficulty.normal=Normal +options.difficulty.hard=Hard +options.difficulty.hardcore=Hardcore +options.graphics=Graphics +options.graphics.fancy=Fancy +options.graphics.fast=Fast +options.guiScale=GUI Scale +options.guiScale.auto=Auto +options.guiScale.small=Small +options.guiScale.normal=Normal +options.guiScale.large=Large +options.advancedOpengl=Advanced OpenGL +options.renderClouds=Clouds +options.farWarning1=A 64 bit Java installation is recommended +options.farWarning2=for 'Far' render distance (you have 32 bit) +options.particles=Particles +options.particles.all=All +options.particles.decreased=Decreased +options.particles.minimal=Minimal +options.chat.title=Chat Settings... +options.chat.visibility=Chat +options.chat.visibility.full=Shown +options.chat.visibility.system=Commands Only +options.chat.visibility.hidden=Hidden +options.chat.color=Colors +options.chat.opacity=Opacity +options.chat.links=Web Links +options.chat.links.prompt=Prompt on Links +options.serverTextures=Server Textures +options.snooper=Allow Snooper +options.snooper.view=Snooper Settings... +options.snooper.title=Machine Specs Collection +options.snooper.desc=We want to collect information about your machine to help improve Minecraft by knowing what we can support and where the biggest problems are. All of this information is completely anonymous and viewable below. We promise we won't do anything bad with this data, but if you want to opt out then feel free to toggle it off! +options.fullscreen=Fullscreen +options.vsync=Use VSync + +performance.max=Max FPS +performance.balanced=Balanced +performance.powersaver=Power saver + +controls.title=Controls + +key.forward=Forward +key.left=Left +key.back=Back +key.right=Right +key.jump=Jump +key.inventory=Inventory +key.drop=Drop +key.chat=Chat +key.fog=Toggle Fog +key.sneak=Sneak +key.playerlist=List Players +key.attack=Attack +key.use=Use Item +key.pickItem=Pick Block +key.mouseButton=Button %1$s +key.command=Command + +texturePack.openFolder=Open texture pack folder +texturePack.title=Select Texture Pack +texturePack.folderInfo=(Place texture pack files here) + +book.pageIndicator=Page %1$s of %2$s +book.byAuthor=by %1$s +book.signButton=Sign +book.editTitle=Enter Book Title: +book.finalizeButton=Sign and Close +book.finalizeWarning=Note! When you sign the book, it will no longer be editable. + +tile.stone.name=Stone +tile.grass.name=Grass Block +tile.dirt.name=Dirt +tile.stonebrick.name=Cobblestone +tile.wood.name=Wooden Planks +tile.wood.oak.name=Oak Wood Planks +tile.wood.spruce.name=Spruce Wood Planks +tile.wood.birch.name=Birch Wood Planks +tile.wood.jungle.name=Jungle Wood Planks +tile.sapling.oak.name=Oak Sapling +tile.sapling.spruce.name=Spruce Sapling +tile.sapling.birch.name=Birch Sapling +tile.sapling.jungle.name=Jungle Sapling +tile.deadbush.name=Dead Bush +tile.bedrock.name=Bedrock +tile.water.name=Water +tile.lava.name=Lava +tile.sand.name=Sand +tile.sandStone.name=Sandstone +tile.sandStone.default.name=Sandstone +tile.sandStone.chiseled.name=Chiseled Sandstone +tile.sandStone.smooth.name=Smooth Sandstone +tile.gravel.name=Gravel +tile.oreGold.name=Gold Ore +tile.oreIron.name=Iron Ore +tile.oreCoal.name=Coal Ore +tile.log.name=Wood +tile.log.oak.name=Oak Wood +tile.log.spruce.name=Spruce Wood +tile.log.birch.name=Birch Wood +tile.log.jungle.name=Jungle Wood +tile.leaves.name=Leaves +tile.leaves.oak.name=Oak Leaves +tile.leaves.spruce.name=Spruce Leaves +tile.leaves.birch.name=Birch Leaves +tile.leaves.jungle.name=Jungle Leaves +tile.tallgrass.name=Grass +tile.tallgrass.shrub.name=Shrub +tile.tallgrass.grass.name=Grass +tile.tallgrass.fern.name=Fern +tile.sponge.name=Sponge +tile.glass.name=Glass +tile.thinGlass.name=Glass Pane +tile.cloth.name=Wool +tile.flower.name=Flower +tile.rose.name=Rose +tile.mushroom.name=Mushroom +tile.blockGold.name=Block of Gold +tile.blockIron.name=Block of Iron +tile.stoneSlab.stone.name=Stone Slab +tile.stoneSlab.sand.name=Sandstone Slab +tile.stoneSlab.wood.name=Wooden Slab +tile.stoneSlab.cobble.name=Cobblestone Slab +tile.stoneSlab.brick.name=Bricks Slab +tile.stoneSlab.smoothStoneBrick.name=Stone Bricks Slab +tile.woodSlab.oak.name=Oak Wood Slab +tile.woodSlab.spruce.name=Spruce Wood Slab +tile.woodSlab.birch.name=Birch Wood Slab +tile.woodSlab.jungle.name=Jungle Wood Slab +tile.brick.name=Bricks +tile.tnt.name=TNT +tile.bookshelf.name=Bookshelf +tile.stoneMoss.name=Moss Stone +tile.obsidian.name=Obsidian +tile.torch.name=Torch +tile.fire.name=Fire +tile.mobSpawner.name=Monster Spawner +tile.stairsWood.name=Oak Wood Stairs +tile.stairsWoodSpruce.name=Spruce Wood Stairs +tile.stairsWoodBirch.name=Birch Wood Stairs +tile.stairsWoodJungle.name=Jungle Wood Stairs +tile.chest.name=Chest +tile.redstoneDust.name=Redstone Dust +tile.oreDiamond.name=Diamond Ore +tile.blockDiamond.name=Block of Diamond +tile.workbench.name=Crafting Table +tile.crops.name=Crops +tile.farmland.name=Farmland +tile.furnace.name=Furnace +tile.sign.name=Sign +tile.doorWood.name=Wooden Door +tile.ladder.name=Ladder +tile.rail.name=Rail +tile.goldenRail.name=Powered Rail +tile.detectorRail.name=Detector Rail +tile.stairsStone.name=Stone Stairs +tile.stairsSandStone.name=Sandstone Stairs +tile.lever.name=Lever +tile.pressurePlate.name=Pressure Plate +tile.doorIron.name=Iron Door +tile.oreRedstone.name=Redstone Ore +tile.notGate.name=Redstone Torch +tile.button.name=Button +tile.snow.name=Snow +tile.ice.name=Ice +tile.cactus.name=Cactus +tile.clay.name=Clay +tile.reeds.name=Sugar cane +tile.jukebox.name=Jukebox +tile.fence.name=Fence +tile.fenceGate.name=Fence Gate +tile.pumpkin.name=Pumpkin +tile.litpumpkin.name=Jack 'o' Lantern +tile.hellrock.name=Netherrack +tile.hellsand.name=Soul Sand +tile.lightgem.name=Glowstone +tile.portal.name=Portal +tile.cloth.black.name=Black Wool +tile.cloth.red.name=Red Wool +tile.cloth.green.name=Green Wool +tile.cloth.brown.name=Brown Wool +tile.cloth.blue.name=Blue Wool +tile.cloth.purple.name=Purple Wool +tile.cloth.cyan.name=Cyan Wool +tile.cloth.silver.name=Light Gray Wool +tile.cloth.gray.name=Gray Wool +tile.cloth.pink.name=Pink Wool +tile.cloth.lime.name=Lime Wool +tile.cloth.yellow.name=Yellow Wool +tile.cloth.lightBlue.name=Light Blue Wool +tile.cloth.magenta.name=Magenta Wool +tile.cloth.orange.name=Orange Wool +tile.cloth.white.name=Wool +tile.oreLapis.name=Lapis Lazuli Ore +tile.blockLapis.name=Lapis Lazuli Block +tile.dispenser.name=Dispenser +tile.musicBlock.name=Note Block +tile.cake.name=Cake +tile.bed.name=Bed +tile.bed.occupied=This bed is occupied +tile.bed.noSleep=You can only sleep at night +tile.bed.notSafe=You may not rest now, there are monsters nearby +tile.bed.notValid=Your home bed was missing or obstructed +tile.lockedchest.name=Locked chest +tile.trapdoor.name=Trapdoor +tile.web.name=Cobweb +tile.stonebricksmooth.name=Stone Bricks +tile.stonebricksmooth.default.name=Stone Bricks +tile.stonebricksmooth.mossy.name=Mossy Stone Bricks +tile.stonebricksmooth.cracked.name=Cracked Stone Bricks +tile.stonebricksmooth.chiseled.name=Chiseled Stone Bricks +tile.monsterStoneEgg.stone.name=Stone Monster Egg +tile.monsterStoneEgg.cobble.name=Cobblestone Monster Egg +tile.monsterStoneEgg.brick.name=Stone Brick Monster Egg +tile.pistonBase.name=Piston +tile.pistonStickyBase.name=Sticky Piston +tile.fenceIron.name=Iron Bars +tile.melon.name=Melon +tile.stairsBrick.name=Brick Stairs +tile.stairsStoneBrickSmooth.name=Stone Brick Stairs +tile.vine.name=Vines +tile.netherBrick.name=Nether Brick +tile.netherFence.name=Nether Brick Fence +tile.stairsNetherBrick.name=Nether Brick Stairs +tile.netherStalk.name=Nether Wart +tile.cauldron.name=Cauldron +tile.enchantmentTable.name=Enchantment Table +tile.whiteStone.name=End Stone +tile.endPortalFrame.name=End Portal +tile.mycel.name=Mycelium +tile.waterlily.name=Lily Pad +tile.dragonEgg.name=Dragon Egg +tile.redstoneLight.name=Redstone Lamp +tile.cocoa.name=Cocoa +tile.enderChest.name=Ender Chest +tile.oreRuby.name=Ruby Ore +tile.oreEmerald.name=Emerald Ore +tile.blockEmerald.name=Block of Emerald +tile.tripWire.name=Tripwire +tile.tripWireSource.name=Tripwire Hook + +item.shovelIron.name=Iron Shovel +item.pickaxeIron.name=Iron Pickaxe +item.hatchetIron.name=Iron Axe +item.flintAndSteel.name=Flint and Steel +item.apple.name=Apple +item.cookie.name=Cookie +item.bow.name=Bow +item.arrow.name=Arrow +item.coal.name=Coal +item.charcoal.name=Charcoal +item.diamond.name=Diamond +item.emerald.name=Emerald +item.ingotIron.name=Iron Ingot +item.ingotGold.name=Gold Ingot +item.swordIron.name=Iron Sword +item.swordWood.name=Wooden Sword +item.shovelWood.name=Wooden Shovel +item.pickaxeWood.name=Wooden Pickaxe +item.hatchetWood.name=Wooden Axe +item.swordStone.name=Stone Sword +item.shovelStone.name=Stone Shovel +item.pickaxeStone.name=Stone Pickaxe +item.hatchetStone.name=Stone Axe +item.swordDiamond.name=Diamond Sword +item.shovelDiamond.name=Diamond Shovel +item.pickaxeDiamond.name=Diamond Pickaxe +item.hatchetDiamond.name=Diamond Axe +item.stick.name=Stick +item.bowl.name=Bowl +item.mushroomStew.name=Mushroom Stew +item.swordGold.name=Golden Sword +item.shovelGold.name=Golden Shovel +item.pickaxeGold.name=Golden Pickaxe +item.hatchetGold.name=Golden Axe +item.string.name=String +item.feather.name=Feather +item.sulphur.name=Gunpowder +item.hoeWood.name=Wooden Hoe +item.hoeStone.name=Stone Hoe +item.hoeIron.name=Iron Hoe +item.hoeDiamond.name=Diamond Hoe +item.hoeGold.name=Golden Hoe +item.seeds.name=Seeds +item.seeds_pumpkin.name=Pumpkin Seeds +item.seeds_melon.name=Melon Seeds +item.melon.name=Melon +item.wheat.name=Wheat +item.bread.name=Bread +item.helmetCloth.name=Leather Cap +item.chestplateCloth.name=Leather Tunic +item.leggingsCloth.name=Leather Pants +item.bootsCloth.name=Leather Boots +item.helmetChain.name=Chain Helmet +item.chestplateChain.name=Chain Chestplate +item.leggingsChain.name=Chain Leggings +item.bootsChain.name=Chain Boots +item.helmetIron.name=Iron Helmet +item.chestplateIron.name=Iron Chestplate +item.leggingsIron.name=Iron Leggings +item.bootsIron.name=Iron Boots +item.helmetDiamond.name=Diamond Helmet +item.chestplateDiamond.name=Diamond Chestplate +item.leggingsDiamond.name=Diamond Leggings +item.bootsDiamond.name=Diamond Boots +item.helmetGold.name=Golden Helmet +item.chestplateGold.name=Golden Chestplate +item.leggingsGold.name=Golden Leggings +item.bootsGold.name=Golden Boots +item.flint.name=Flint +item.porkchopRaw.name=Raw Porkchop +item.porkchopCooked.name=Cooked Porkchop +item.chickenRaw.name=Raw Chicken +item.chickenCooked.name=Cooked Chicken +item.beefRaw.name=Raw Beef +item.beefCooked.name=Steak +item.painting.name=Painting +item.appleGold.name=Golden Apple +item.sign.name=Sign +item.doorWood.name=Wooden Door +item.bucket.name=Bucket +item.bucketWater.name=Water Bucket +item.bucketLava.name=Lava Bucket +item.minecart.name=Minecart +item.saddle.name=Saddle +item.doorIron.name=Iron Door +item.redstone.name=Redstone +item.snowball.name=Snowball +item.boat.name=Boat +item.leather.name=Leather +item.milk.name=Milk +item.brick.name=Brick +item.clay.name=Clay +item.reeds.name=Sugar Canes +item.paper.name=Paper +item.book.name=Book +item.slimeball.name=Slimeball +item.minecartChest.name=Minecart with Chest +item.minecartFurnace.name=Minecart with Furnace +item.egg.name=Egg +item.compass.name=Compass +item.fishingRod.name=Fishing Rod +item.clock.name=Clock +item.yellowDust.name=Glowstone Dust +item.fishRaw.name=Raw Fish +item.fishCooked.name=Cooked Fish +item.record.name=Music Disc +item.bone.name=Bone +item.dyePowder.black.name=Ink Sac +item.dyePowder.red.name=Rose Red +item.dyePowder.green.name=Cactus Green +item.dyePowder.brown.name=Cocoa Beans +item.dyePowder.blue.name=Lapis Lazuli +item.dyePowder.purple.name=Purple Dye +item.dyePowder.cyan.name=Cyan Dye +item.dyePowder.silver.name=Light Gray Dye +item.dyePowder.gray.name=Gray Dye +item.dyePowder.pink.name=Pink Dye +item.dyePowder.lime.name=Lime Dye +item.dyePowder.yellow.name=Dandelion Yellow +item.dyePowder.lightBlue.name=Light Blue Dye +item.dyePowder.magenta.name=Magenta Dye +item.dyePowder.orange.name=Orange Dye +item.dyePowder.white.name=Bone Meal +item.sugar.name=Sugar +item.cake.name=Cake +item.bed.name=Bed +item.diode.name=Redstone Repeater +item.map.name=Map +item.leaves.name=Leaves +item.shears.name=Shears +item.rottenFlesh.name=Rotten Flesh +item.enderPearl.name=Ender Pearl +item.blazeRod.name=Blaze Rod +item.ghastTear.name=Ghast Tear +item.netherStalkSeeds.name=Nether Wart +item.potion.name=Potion +item.emptyPotion.name=Water Bottle +item.goldNugget.name=Gold Nugget +item.glassBottle.name=Glass Bottle +item.spiderEye.name=Spider Eye +item.fermentedSpiderEye.name=Fermented Spider Eye +item.blazePowder.name=Blaze Powder +item.magmaCream.name=Magma Cream +item.cauldron.name=Cauldron +item.brewingStand.name=Brewing Stand +item.eyeOfEnder.name=Eye of Ender +item.speckledMelon.name=Glistering Melon +item.monsterPlacer.name=Spawn +item.expBottle.name=Bottle o' Enchanting +item.fireball.name=Fire Charge +item.writingBook.name=Book and Quill +item.writtenBook.name=Written Book +item.ruby.name=Ruby + +container.inventory=Inventory +container.crafting=Crafting +container.dispenser=Dispenser +container.furnace=Furnace +container.enchant=Enchant +container.creative=Item Selection +container.brewing=Brewing Stand +container.chest=Chest +container.chestDouble=Large Chest +container.minecart=Minecart +container.enderchest=Ender Chest + +entity.Item.name=Item +entity.XPOrb.name=Experience Orb + +entity.Arrow.name=Arrow +entity.Snowball.name=Snowball +entity.Painting.name=Painting + +entity.Mob.name=Mob +entity.Monster.name=Monster + +entity.Creeper.name=Creeper +entity.Skeleton.name=Skeleton +entity.Spider.name=Spider +entity.Giant.name=Giant +entity.Zombie.name=Zombie +entity.Slime.name=Slime +entity.Ghast.name=Ghast +entity.PigZombie.name=Zombie Pigman +entity.Enderman.name=Enderman +entity.Silverfish.name=Silverfish +entity.CaveSpider.name=Cave Spider +entity.Blaze.name=Blaze +entity.LavaSlime.name=Magma Cube +entity.MushroomCow.name=Mooshroom +entity.Villager.name=Villager +entity.VillagerGolem.name=Iron Golem +entity.SnowMan.name=Snow Golem +entity.EnderDragon.name=Ender Dragon + +entity.Pig.name=Pig +entity.Sheep.name=Sheep +entity.Cow.name=Cow +entity.Chicken.name=Chicken +entity.Squid.name=Squid +entity.Wolf.name=Wolf +entity.Ozelot.name=Ocelot +entity.Cat.name=Cat + +entity.PrimedTnt.name=Block of TNT +entity.FallingSand.name=Falling Block + +entity.Minecart.name=Minecart +entity.Boat.name=Boat + +entity.Arrow.name=arrow +entity.generic.name=unknown + +death.inFire=%1$s went up in flames +death.onFire=%1$s burned to death +death.lava=%1$s tried to swim in lava +death.inWall=%1$s suffocated in a wall +death.drown=%1$s drowned +death.starve=%1$s starved to death +death.cactus=%1$s was pricked to death +death.fall=%1$s hit the ground too hard +death.outOfWorld=%1$s fell out of the world +death.generic=%1$s died +death.explosion=%1$s blew up +death.magic=%1$s was killed by magic +death.mob=%1$s was slain by %2$s +death.player=%1$s was slain by %2$s +death.arrow=%1$s was shot by %2$s +death.fireball=%1$s was fireballed by %2$s +death.thrown=%1$s was pummeled by %2$s +death.indirectMagic=%1$s was killed by %2$s + +deathScreen.respawn=Respawn +deathScreen.deleteWorld=Delete world +deathScreen.titleScreen=Title screen +deathScreen.score=Score +deathScreen.title.hardcore=Game over! +deathScreen.hardcoreInfo=You cannot respawn in hardcore mode! +deathScreen.title=You died! +deathScreen.leaveServer=Leave server + +potion.empty=No Effects +potion.moveSpeed=Speed +potion.moveSlowdown=Slowness +potion.digSpeed=Haste +potion.digSlowDown=Mining Fatigue +potion.damageBoost=Strength +potion.weakness=Weakness +potion.heal=Instant Health +potion.harm=Instant Damage +potion.jump=Jump Boost +potion.confusion=Nausea +potion.regeneration=Regeneration +potion.resistance=Resistance +potion.fireResistance=Fire Resistance +potion.waterBreathing=Water Breathing +potion.invisibility=Invisibility +potion.blindness=Blindness +potion.nightVision=Night Vision +potion.hunger=Hunger +potion.poison=Poison + +potion.moveSpeed.postfix=Potion of Swiftness +potion.moveSlowdown.postfix=Potion of Slowness +potion.digSpeed.postfix=Potion of Haste +potion.digSlowDown.postfix=Potion of Dullness +potion.damageBoost.postfix=Potion of Strength +potion.weakness.postfix=Potion of Weakness +potion.heal.postfix=Potion of Healing +potion.harm.postfix=Potion of Harming +potion.jump.postfix=Potion of Leaping +potion.confusion.postfix=Potion of Nausea +potion.regeneration.postfix=Potion of Regeneration +potion.resistance.postfix=Potion of Resistance +potion.fireResistance.postfix=Potion of Fire Resistance +potion.waterBreathing.postfix=Potion of Water Breathing +potion.invisibility.postfix=Potion of Invisibility +potion.blindness.postfix=Potion of Blindness +potion.nightVision.postfix=Potion of Night Vision +potion.hunger.postfix=Potion of Hunger +potion.poison.postfix=Potion of Poison + +potion.potency.0= +potion.potency.1=II +potion.potency.2=III +potion.potency.3=IV + +potion.prefix.grenade=Splash +potion.prefix.mundane=Mundane +potion.prefix.uninteresting=Uninteresting +potion.prefix.bland=Bland +potion.prefix.clear=Clear +potion.prefix.milky=Milky +potion.prefix.diffuse=Diffuse +potion.prefix.artless=Artless +potion.prefix.thin=Thin +potion.prefix.awkward=Awkward +potion.prefix.flat=Flat +potion.prefix.bulky=Bulky +potion.prefix.bungling=Bungling +potion.prefix.buttered=Buttered +potion.prefix.smooth=Smooth +potion.prefix.suave=Suave +potion.prefix.debonair=Debonair +potion.prefix.thick=Thick +potion.prefix.elegant=Elegant +potion.prefix.fancy=Fancy +potion.prefix.charming=Charming +potion.prefix.dashing=Dashing +potion.prefix.refined=Refined +potion.prefix.cordial=Cordial +potion.prefix.sparkling=Sparkling +potion.prefix.potent=Potent +potion.prefix.foul=Foul +potion.prefix.odorless=Odorless +potion.prefix.rank=Rank +potion.prefix.harsh=Harsh +potion.prefix.acrid=Acrid +potion.prefix.gross=Gross +potion.prefix.stinky=Stinky + +enchantment.damage.all=Sharpness +enchantment.damage.undead=Smite +enchantment.damage.arthropods=Bane of Arthropods +enchantment.knockback=Knockback +enchantment.fire=Fire Aspect +enchantment.protect.all=Protection +enchantment.protect.fire=Fire Protection +enchantment.protect.fall=Feather Falling +enchantment.protect.explosion=Blast Protection +enchantment.protect.projectile=Projectile Protection +enchantment.oxygen=Respiration +enchantment.waterWorker=Aqua Affinity +enchantment.digging=Efficiency +enchantment.untouching=Silk Touch +enchantment.durability=Unbreaking +enchantment.lootBonus=Looting +enchantment.lootBonusDigger=Fortune +enchantment.arrowDamage=Power +enchantment.arrowFire=Flame +enchantment.arrowKnockback=Punch +enchantment.arrowInfinite=Infinity + +enchantment.level.1=I +enchantment.level.2=II +enchantment.level.3=III +enchantment.level.4=IV +enchantment.level.5=V +enchantment.level.6=VI +enchantment.level.7=VII +enchantment.level.8=VIII +enchantment.level.9=IX +enchantment.level.10=X + +gui.achievements=Achievements +gui.stats=Statistics + +stat.generalButton=General +stat.blocksButton=Blocks +stat.itemsButton=Items + +stat.used=Times Used +stat.mined=Times Mined +stat.depleted=Times Depleted +stat.crafted=Times Crafted + +stat.startGame=Times played +stat.createWorld=Worlds played +stat.loadWorld=Saves loaded +stat.joinMultiplayer=Multiplayer joins +stat.leaveGame=Games quit + +stat.playOneMinute=Minutes Played + +stat.walkOneCm=Distance Walked +stat.fallOneCm=Distance Fallen +stat.swimOneCm=Distance Swum +stat.flyOneCm=Distance Flown +stat.climbOneCm=Distance Climbed +stat.diveOneCm=Distance Dove +stat.minecartOneCm=Distance by Minecart +stat.boatOneCm=Distance by Boat +stat.pigOneCm=Distance by Pig +stat.jump=Jumps +stat.drop=Items Dropped + +stat.damageDealt=Damage Dealt +stat.damageTaken=Damage Taken +stat.deaths=Number of Deaths +stat.mobKills=Mob Kills +stat.playerKills=Player Kills +stat.fishCaught=Fish Caught + +stat.mineBlock=%1$s Mined +stat.craftItem=%1$s Crafted +stat.useItem=%1$s Used +stat.breakItem=%1$s Depleted + +achievement.get=Achievement get! + +achievement.taken=Taken! + +achievement.requires=Requires '%1$s' +achievement.openInventory=Taking Inventory +achievement.openInventory.desc=Press '%1$s' to open your inventory. +achievement.mineWood=Getting Wood +achievement.mineWood.desc=Attack a tree until a block of wood pops out +achievement.buildWorkBench=Benchmarking +achievement.buildWorkBench.desc=Craft a workbench with four blocks of planks +achievement.buildPickaxe=Time to Mine! +achievement.buildPickaxe.desc=Use planks and sticks to make a pickaxe +achievement.buildFurnace=Hot Topic +achievement.buildFurnace.desc=Construct a furnace out of eight stone blocks +achievement.acquireIron=Acquire Hardware +achievement.acquireIron.desc=Smelt an iron ingot +achievement.buildHoe=Time to Farm! +achievement.buildHoe.desc=Use planks and sticks to make a hoe +achievement.makeBread=Bake Bread +achievement.makeBread.desc=Turn wheat into bread +achievement.bakeCake=The Lie +achievement.bakeCake.desc=Wheat, sugar, milk and eggs! +achievement.buildBetterPickaxe=Getting an Upgrade +achievement.buildBetterPickaxe.desc=Construct a better pickaxe +achievement.cookFish=Delicious Fish +achievement.cookFish.desc=Catch and cook fish! +achievement.onARail=On A Rail +achievement.onARail.desc=Travel by minecart at least 1 km from where you started +achievement.buildSword=Time to Strike! +achievement.buildSword.desc=Use planks and sticks to make a sword +achievement.killEnemy=Monster Hunter +achievement.killEnemy.desc=Attack and destroy a monster +achievement.killCow=Cow Tipper +achievement.killCow.desc=Harvest some leather +achievement.flyPig=When Pigs Fly +achievement.flyPig.desc=Fly a pig off a cliff +achievement.snipeSkeleton=Sniper Duel +achievement.snipeSkeleton.desc=Kill a skeleton with an arrow from more than 50 meters +achievement.diamonds=DIAMONDS! +achievement.diamonds.desc=Acquire diamonds with your iron tools +achievement.portal=We Need to Go Deeper +achievement.portal.desc=Build a portal to the Nether +achievement.ghast=Return to Sender +achievement.ghast.desc=Destroy a Ghast with a fireball +achievement.blazeRod=Into Fire +achievement.blazeRod.desc=Relieve a Blaze of its rod +achievement.potion=Local Brewery +achievement.potion.desc=Brew a potion +achievement.theEnd=The End? +achievement.theEnd.desc=Locate the End +achievement.theEnd2=The End. +achievement.theEnd2.desc=Defeat the Ender Dragon +achievement.enchantments=Enchanter +achievement.enchantments.desc=Use a book, obsidian and diamonds to construct an enchantment table +achievement.overkill=Overkill +achievement.overkill.desc=Deal eight hearts of damage in a single hit +achievement.bookcase=Librarian +achievement.bookcase.desc=Build some bookshelves to improve your enchantment table + +commands.generic.exception=An unknown error occurred while attempting to perform this command +commands.generic.syntax=Invalid command syntax +commands.generic.player.notFound=That player cannot be found +commands.generic.notFound=Unknown command. Try /help for a list of commands. +commands.generic.num.invalid='%s' is not a valid number +commands.generic.num.tooSmall=The number you have entered (%d) is too small, it must be at least %d +commands.generic.num.tooBig=The number you have entered (%d) is too big, it must be at most %d +commands.generic.usage=Usage: %s +commands.xp.success=Given %d experience to %s +commands.xp.usage=/xp [player] +commands.give.usage=/give [amount] [data] +commands.give.notFound=There is no such item with ID %d +commands.give.success=Given %s (ID %d) * %d to %s +commands.downfall.success=Toggled downfall +commands.time.usage=/time +commands.time.added=Added %d to the time +commands.time.set=Set the time to %d +commands.players.list=There are %d/%d players online: +commands.banlist.ips=There are %d total banned IP addresses: +commands.banlist.players=There are %d total banned players: +commands.banlist.usage=/banlist [ips|players] +commands.kick.success=Kicked %s from the game +commands.kick.success.reason=Kicked %s from the game: '%s' +commands.kick.usage=/kick [reason ...] +commands.op.success=Opped %s +commands.op.usage=/op +commands.deop.success=De-opped %s +commands.deop.usage=/deop +commands.say.usage=/say +commands.ban.success=Banned player %s +commands.ban.usage=/ban [reason ...] +commands.unban.success=Unbanned player %s +commands.unban.usage=/pardon +commands.banip.invalid=You have entered an invalid IP address or a player that is not online +commands.banip.success=Banned IP address %s +commands.banip.success.players=Banned IP address %s belonging to %s +commands.banip.usage=/ban-ip [reason ...] +commands.unbanip.invalid=You have entered an invalid IP address +commands.unbanip.success=Unbanned IP address %s +commands.unbanip.usage=/pardon-ip
+commands.save.enabled=Turned on world auto-saving +commands.save.disabled=Turned off world auto-saving +commands.save.start=Saving... +commands.save.success=Saved the world +commands.save.failed=Saving failed: %s +commands.stop.start=Stopping the server +commands.tp.success=Teleported %s to %s +commands.tp.coordinates=Teleported %s to %d,%d,%d +commands.tp.usage=/tp [target player] OR /tp [target player] +commands.whitelist.list=There are %d (out of %d seen) whitelisted players: +commands.whitelist.enabled=Turned on the whitelist +commands.whitelist.disabled=Turned off the whitelist +commands.whitelist.reloaded=Reloaded the whitelist +commands.whitelist.add.success=Added %s to the whitelist +commands.whitelist.add.usage=/whitelist add +commands.whitelist.remove.success=Removed %s from the whitelist +commands.whitelist.remove.usage=/whitelist remove +commands.whitelist.usage=/whitelist +commands.gamemode.success.self=Set own game mode to %s +commands.gamemode.success.other=Set %s's game mode to %s +commands.gamemode.usage=/gamemode [player] +commands.defaultgamemode.usage=/defaultgamemode +commands.defaultgamemode.success=The world's default game mode is now %s +commands.me.usage=/me +commands.help.header=--- Showing help page %d of %d (/help ) --- +commands.help.footer=Tip: Use the key while typing a command to auto-complete the command or its arguments +commands.help.usage=/help [page|command name] +commands.publish.started=Local game hosted on %s +commands.publish.failed=Unable to host local game +commands.debug.start=Started debug profiling +commands.debug.stop=Stopped debug profiling after %.2f seconds (%d ticks) +commands.debug.notStarted=Can't stop profiling when we haven't started yet! +commands.debug.usage=/debug + +itemGroup.buildingBlocks=Building Blocks +itemGroup.decorations=Decoration Blocks +itemGroup.redstone=Redstone +itemGroup.transportation=Transportation +itemGroup.misc=Miscellaneous +itemGroup.search=Search Items +itemGroup.food=Foodstuffs +itemGroup.tools=Tools +itemGroup.combat=Combat +itemGroup.brewing=Brewing +itemGroup.materials=Materials +itemGroup.inventory=Survival Inventory + +inventory.binSlot=Destroy Item diff --git a/Minecraft.World/Util/Language.cpp b/Minecraft.World/Util/Language.cpp index 9ffbf4c2f..d3784d179 100644 --- a/Minecraft.World/Util/Language.cpp +++ b/Minecraft.World/Util/Language.cpp @@ -1,54 +1,124 @@ #include "../Platform/stdafx.h" #include "Language.h" +#include "../IO/Files/File.h" +#include "../IO/Files/FileInputStream.h" // 4J - TODO - properly implement +// 4jcraft: done! -Language *Language::singleton = nullptr; +Language* Language::singleton = nullptr; -Language::Language() -{ +Language::Language() { + // TODO: move the language loading out of the init to better match 1.3.x + // see StringTranslate.java in MCP 7.x for more context + File langFile(L"Common/res/lang/en_US.lang"); + if (langFile.exists()) { + InputStream* stream = new FileInputStream(langFile); + if (stream) { + __int64 fileSize = langFile.length(); + if (fileSize > 0) { + // 4jcraft: we would've used BufferedReader like the JE + // equivalent here, but the lang file starts with a newline, + // causing readLine() in this BufferedReader impl to just return + // an empty string + // + // InputStreamReader reader(stream); + // BufferedReader bufferedReader(&reader); + // std::wstring line; + byteArray buffer((unsigned int)fileSize); + int bytesRead = stream->read(buffer, 0, (unsigned int)fileSize); + if (bytesRead > 0) { + std::string content(reinterpret_cast(buffer.data), + bytesRead); + std::istringstream iss(content); + std::string line; + + // while (!(line = bufferedReader.readLine()).empty()) { + while (std::getline(iss, line)) { + size_t start = line.find_first_not_of(" \t\r\n"); + if (start == std::string::npos) continue; + + size_t end = line.find_last_not_of(" \t\r\n"); + std::string trimmed = + line.substr(start, end - start + 1); + + if (trimmed.empty() || trimmed[0] == '#') continue; + + size_t equalsPos = trimmed.find('='); + if (equalsPos != std::string::npos) { + std::string key = trimmed.substr(0, equalsPos); + std::string value = trimmed.substr(equalsPos + 1); + + std::wstring wkey(key.begin(), key.end()); + std::wstring wvalue(value.begin(), value.end()); + + translateTable[wkey] = wvalue; + } + } + } + } + delete stream; + } + } } -Language *Language::getInstance() -{ - // 4jcraft, fixes static init fiassco in I18n.cpp - if(singleton == nullptr) { - singleton = new Language(); - } +Language* Language::getInstance() { + // 4jcraft, fixes static init fiassco in I18n.cpp + if (singleton == nullptr) { + singleton = new Language(); + } - return singleton; + return singleton; } /* 4J Jev, creates 2 identical functions. std::wstring Language::getElement(const std::wstring& elementId) { - return elementId; + return elementId; } */ // 4jcraft changed, again const reference into va_start, std forbids -std::wstring Language::getElement(std::wstring elementId, ...) -{ -#ifdef __PSVITA__ // 4J - vita doesn't like having a reference type as the last parameter passed to va_start - we shouldn't need this method anyway - return L""; +std::wstring Language::getElement(std::wstring elementId, ...) { +#ifdef __PSVITA__ // 4J - vita doesn't like having a reference type as the last + // parameter passed to va_start - we shouldn't need this + // method anyway + return L""; #else - va_list args; - va_start(args, elementId); - return getElement(elementId, args); + va_list args; + va_start(args, elementId); + std::wstring result = getElement(elementId, args); + va_end(args); + return result; #endif } -std::wstring Language::getElement(const std::wstring& elementId, va_list args) -{ - // 4J TODO - return elementId; +std::wstring Language::getElement(const std::wstring& elementId, va_list args) { + auto it = translateTable.find(elementId); + std::wstring formatString = + (it != translateTable.end()) ? it->second : elementId; + + if (formatString.find(L'%') != std::wstring::npos) { + int bufferSize = formatString.length() + 256; + std::vector buffer(bufferSize); + + int written = + vswprintf(buffer.data(), bufferSize, formatString.c_str(), args); + if (written >= 0) { + return std::wstring(buffer.data(), written); + } + } + + return formatString; } -std::wstring Language::getElementName(const std::wstring& elementId) -{ - return elementId; +std::wstring Language::getElementName(const std::wstring& elementId) { + std::wstring nameKey = elementId + L".name"; + auto it = translateTable.find(nameKey); + return (it != translateTable.end()) ? it->second : elementId; } -std::wstring Language::getElementDescription(const std::wstring& elementId) -{ - return elementId; +std::wstring Language::getElementDescription(const std::wstring& elementId) { + std::wstring descKey = elementId + L".description"; + auto it = translateTable.find(descKey); + return (it != translateTable.end()) ? it->second : elementId; } diff --git a/Minecraft.World/Util/Language.h b/Minecraft.World/Util/Language.h index b04ede3d1..e47f8deb5 100644 --- a/Minecraft.World/Util/Language.h +++ b/Minecraft.World/Util/Language.h @@ -1,14 +1,15 @@ #pragma once -class Language -{ +class Language { private: - static Language *singleton; + static Language* singleton; + std::unordered_map translateTable; + public: - Language(); - static Language *getInstance(); + Language(); + static Language* getInstance(); std::wstring getElement(std::wstring elementId, ...); - std::wstring getElement(const std::wstring& elementId, va_list args); + std::wstring getElement(const std::wstring& elementId, va_list args); std::wstring getElementName(const std::wstring& elementId); std::wstring getElementDescription(const std::wstring& elementId); }; From fae7ebe7fa51f9064faa55d873cf0d51709d32ec Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Sun, 15 Mar 2026 18:29:09 +0300 Subject: [PATCH 20/29] feat(jui): new multiline container item tooltips Backported from Java Edition 1.3.x This replaces the old non-functional tooltips --- .../UI/Screens/AbstractContainerScreen.cpp | 145 ++++++++++++++++-- 1 file changed, 133 insertions(+), 12 deletions(-) diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp index 13376b7d7..b88d66eb9 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp @@ -93,22 +93,143 @@ void AbstractContainerScreen::render(int xm, int ym, float a) renderLabels(); - if (inventory->getCarried() == NULL && hoveredSlot != NULL && hoveredSlot->hasItem()) - { + // 4jcraft: newer tooltips backported from java edition 1.3.x (MCP 7.x) + if (inventory->getCarried() == NULL && hoveredSlot != NULL && + hoveredSlot->hasItem()) { + std::shared_ptr item = hoveredSlot->getItem(); - // std::wstring elementName = trimString(Language::getInstance()->getElementName(hoveredSlot->getItem()->getDescriptionId())); - std::wstring elementName = L""; + // std::wstring elementName = + // trimString(Language::getInstance()->getElementName(hoveredSlot->getItem()->getDescriptionId())); + std::vector elementName; + std::vector* tooltipLines = + item->getHoverText(minecraft->player, false, elementName); - if (elementName.length() > 0) - { - int x = xm - xo + 12; - int y = ym - yo - 12; - int width = font->width(elementName); - fillGradient(x - 3, y - 3, x + width + 3, y + 8 + 3, 0xc0000000, 0xc0000000); + if (tooltipLines != NULL && tooltipLines->size() > 0) { + int tooltipWidth = 0; + std::vector cleanedLines; + std::vector lineColors; - font->drawShadow(elementName, x, y, 0xffffffff); + for (int lineIndex = 0; lineIndex < (int)tooltipLines->size(); + ++lineIndex) { + std::wstring rawLine = (*tooltipLines)[lineIndex]; + std::wstring clean = L""; + int lineColor = 0xffffffff; + + // 4jcraft: LCE is using HTML font elements for its tooltip + // colors, so make sure to parse them for parity w iggy UI + // + // examples would be enchantment books, potions and music + // discs + size_t fontPos = rawLine.find(L"') { + inTag = false; + } else if (!inTag) { + clean += currentChar; + } + } + + cleanedLines.push_back(clean); + lineColors.push_back(lineColor); + + int lineWidth = font->width(clean); + if (lineWidth > tooltipWidth) { + tooltipWidth = lineWidth; + } + } + + int tooltipX = xm - xo + 12; + int tooltipY = ym - yo - 12; + + int tooltipHeight = 8; + + if (tooltipLines->size() > 1) { + tooltipHeight += 2 + (tooltipLines->size() - 1) * 10; + } + + int bgColor = 0xf0100010; + fillGradient(tooltipX - 3, tooltipY - 4, + tooltipX + tooltipWidth + 3, tooltipY - 3, bgColor, + bgColor); + fillGradient(tooltipX - 3, tooltipY + tooltipHeight + 3, + tooltipX + tooltipWidth + 3, + tooltipY + tooltipHeight + 4, bgColor, bgColor); + fillGradient(tooltipX - 3, tooltipY - 3, + tooltipX + tooltipWidth + 3, + tooltipY + tooltipHeight + 3, bgColor, bgColor); + fillGradient(tooltipX - 4, tooltipY - 3, tooltipX - 3, + tooltipY + tooltipHeight + 3, bgColor, bgColor); + fillGradient(tooltipX + tooltipWidth + 3, tooltipY - 3, + tooltipX + tooltipWidth + 4, + tooltipY + tooltipHeight + 3, bgColor, bgColor); + + int borderStart = 0x505000ff; + int borderFinish = + (borderStart & 0xfefefe) >> 1 | borderStart & 0xff000000; + fillGradient(tooltipX - 3, (tooltipY - 3) + 1, (tooltipX - 3) + 1, + (tooltipY + tooltipHeight + 3) - 1, borderStart, + borderFinish); + fillGradient(tooltipX + tooltipWidth + 2, (tooltipY - 3) + 1, + tooltipX + tooltipWidth + 3, + (tooltipY + tooltipHeight + 3) - 1, borderStart, + borderFinish); + fillGradient(tooltipX - 3, tooltipY - 3, + tooltipX + tooltipWidth + 3, (tooltipY - 3) + 1, + borderStart, borderStart); + fillGradient(tooltipX - 3, tooltipY + tooltipHeight + 2, + tooltipX + tooltipWidth + 3, + tooltipY + tooltipHeight + 3, borderFinish, + borderFinish); + + int currentY = tooltipY; + for (int lineIndex = 0; lineIndex < (int)tooltipLines->size(); + ++lineIndex) { + std::wstring& currentLine = cleanedLines[lineIndex]; + int textColor; + + if (lineIndex == 0) { + textColor = app.GetHTMLColour(item->getRarity()->color); + } else { + textColor = (lineColors[lineIndex] != 0xffffffff) + ? lineColors[lineIndex] + : 0xffaaaaaa; + } + + font->drawShadow(currentLine, tooltipX, currentY, textColor); + + if (lineIndex == 0) { + currentY += 2; + } + + currentY += 10; + } } - } glPopMatrix(); From 0c5a300b1ce771a62df3f0fdcb71ff5dac09104b Mon Sep 17 00:00:00 2001 From: jerryjhird Date: Sun, 15 Mar 2026 08:16:47 +0000 Subject: [PATCH 21/29] added brightness and FOV sliders to grahpic settings as well as changed weird text in PauseScreen (also adds sliding logic to sliders so you can drag them with your mouse) --- Minecraft.Client/UI/Screens/PauseScreen.cpp | 4 +- .../UI/Screens/VideoSettingsScreen.cpp | 52 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Minecraft.Client/UI/Screens/PauseScreen.cpp b/Minecraft.Client/UI/Screens/PauseScreen.cpp index 5fafa8561..30e2c7904 100644 --- a/Minecraft.Client/UI/Screens/PauseScreen.cpp +++ b/Minecraft.Client/UI/Screens/PauseScreen.cpp @@ -30,8 +30,8 @@ void PauseScreen::init() } - buttons.push_back(new Button(4, width / 2 - 100, height / 4 + 24 * 1 + yo, L"LBack to game")); - buttons.push_back(new Button(0, width / 2 - 100, height / 4 + 24 * 4 + yo, L"LOptions...")); + buttons.push_back(new Button(4, width / 2 - 100, height / 4 + 24 * 1 + yo, I18n::get(L"menu.returnToGame"))); + buttons.push_back(new Button(0, width / 2 - 100, height / 4 + 24 * 4 + yo, I18n::get(L"menu.options"))); buttons.push_back(new Button(5, width / 2 - 100, height / 4 + 24 * 2 + yo, 98, 20, I18n::get(L"gui.achievements"))); buttons.push_back(new Button(6, width / 2 + 2, height / 4 + 24 * 2 + yo, 98, 20, I18n::get(L"gui.stats"))); diff --git a/Minecraft.Client/UI/Screens/VideoSettingsScreen.cpp b/Minecraft.Client/UI/Screens/VideoSettingsScreen.cpp index 2b765d59f..a7c0d87f3 100644 --- a/Minecraft.Client/UI/Screens/VideoSettingsScreen.cpp +++ b/Minecraft.Client/UI/Screens/VideoSettingsScreen.cpp @@ -18,28 +18,38 @@ void VideoSettingsScreen::init() Language *language = Language::getInstance(); this->title = language->getElement(L"options.videoTitle"); - // 4J - this was as static array but moving it into the function to remove any issues with static initialisation order - const Options::Option *items[8] = { - Options::Option::GRAPHICS, Options::Option::RENDER_DISTANCE, Options::Option::AMBIENT_OCCLUSION, Options::Option::FRAMERATE_LIMIT, Options::Option::ANAGLYPH, Options::Option::VIEW_BOBBING, - Options::Option::GUI_SCALE, Options::Option::ADVANCED_OPENGL - }; + const Options::Option *items[10] = { + Options::Option::GRAPHICS, + Options::Option::RENDER_DISTANCE, + Options::Option::AMBIENT_OCCLUSION, + Options::Option::FRAMERATE_LIMIT, + Options::Option::ANAGLYPH, + Options::Option::VIEW_BOBBING, + Options::Option::GUI_SCALE, + Options::Option::ADVANCED_OPENGL, + Options::Option::GAMMA, + Options::Option::FOV + }; + + for (int i = 0; i < 10; i++) + { + const Options::Option *item = items[i]; + int xPos = width / 2 - 155 + (i % 2 * 160); + int yPos = height / 6 + 24 * (i / 2); - for (int position = 0; position < 8; position++) - { - const Options::Option *item = items[position]; if (!item->isProgress()) - { - buttons.push_back(new SmallButton(item->getId(), width / 2 - 155 + position % 2 * 160, height / 6 + 24 * (position >> 1), item, options->getMessage(item))); + { + buttons.push_back(new SmallButton(item->getId(), xPos, yPos, item, options->getMessage(item))); } - else - { - buttons.push_back(new SlideButton(item->getId(), width / 2 - 155 + position % 2 * 160, height / 6 + 24 * (position >> 1), item, options->getMessage(item), options->getProgressValue(item))); + else + { + buttons.push_back(new SlideButton(item->getId(), xPos, yPos, item, options->getMessage(item), options->getProgressValue(item))); } } // buttons.add(new Button(VIDEO_BUTTON_ID, width / 2 - 100, height / 6 + 24 * 4 + 12, language.getElement("options.video"))); // buttons.add(new Button(CONTROLS_BUTTON_ID, width / 2 - 100, height / 6 + 24 * 5 + 12, language.getElement("options.controls"))); - buttons.push_back(new Button(200, width / 2 - 100, height / 6 + 24 * 7, language->getElement(L"gui.done"))); + buttons.push_back(new Button(200, width / 2 - 100, height / 6 + 24 * 6, language->getElement(L"gui.done"))); } @@ -47,25 +57,23 @@ void VideoSettingsScreen::buttonClicked(Button *button) { if (!button->active) return; if (button->id < 100 && (dynamic_cast(button) != NULL)) - { + { options->toggle(((SmallButton *) button)->getOption(), 1); button->msg = options->getMessage(Options::Option::getItem(button->id)); + return; } if (button->id == 200) - { + { minecraft->options->save(); minecraft->setScreen(lastScreen); + return; } - - ScreenSizeCalculator ssc(minecraft->options, minecraft->width, minecraft->height); - int screenWidth = ssc.getWidth(); - int screenHeight = ssc.getHeight(); - Screen::init(minecraft, screenWidth, screenHeight); // 4J - was this.init } void VideoSettingsScreen::render(int xm, int ym, float a) { renderBackground(); drawCenteredString(font, title, width / 2, 20, 0xffffff); + Screen::render(xm, ym, a); -} +} \ No newline at end of file From d6ee57f3e6fd3c7aab4fc6d8821cbb4dd8d02aa7 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 16:28:44 +0300 Subject: [PATCH 22/29] fix: disable java GUI by default as to not conflict with the iggy UI --- meson.options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.options b/meson.options index 6b739b375..74de97f98 100644 --- a/meson.options +++ b/meson.options @@ -1,6 +1,6 @@ option('enable_java_guis', type : 'boolean', - value : true, + value : false, description : 'Re-enable the Java UI remnants in the code (for testing only)') option('enable_vsync', From 6d0d4b2ed14ef3e42d523b7fc33fc7a50f598c3a Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 17:24:11 +0300 Subject: [PATCH 23/29] fix(textures): remove ENABLE_JAVA_GUIS conditionals Fixes entities not using the correct textures when java GUI is enabled --- Minecraft.Client/Textures/Textures.cpp | 6 ------ Minecraft.Client/Textures/Textures.h | 6 ------ 2 files changed, 12 deletions(-) diff --git a/Minecraft.Client/Textures/Textures.cpp b/Minecraft.Client/Textures/Textures.cpp index 69408c942..36799baaf 100644 --- a/Minecraft.Client/Textures/Textures.cpp +++ b/Minecraft.Client/Textures/Textures.cpp @@ -30,19 +30,14 @@ C4JRender::eTextureFormat Textures::TEXTURE_FORMAT = int Textures::preLoadedIdx[TN_COUNT]; const wchar_t* Textures::preLoaded[TN_COUNT] = { L"%blur%misc/pumpkinblur", -#ifdef ENABLE_JAVA_GUIS L"%blur%/misc/vignette", // Not currently used -#endif L"%clamp%misc/shadow", -#ifdef ENABLE_JAVA_GUIS L"/achievement/bg", // Not currently used -#endif L"art/kz", L"environment/clouds", L"environment/rain", L"environment/snow", L"gui/gui", -#ifdef ENABLE_JAVA_GUIS L"gui/background", L"gui/inventory", L"gui/container", @@ -53,7 +48,6 @@ const wchar_t* Textures::preLoaded[TN_COUNT] = { L"gui/creative_inventory/tab_inventory", L"gui/creative_inventory/tab_item_search", L"title/mclogo", -#endif L"gui/icons", L"item/arrows", L"item/boat", diff --git a/Minecraft.Client/Textures/Textures.h b/Minecraft.Client/Textures/Textures.h index e91f4d581..2ee3247ca 100644 --- a/Minecraft.Client/Textures/Textures.h +++ b/Minecraft.Client/Textures/Textures.h @@ -15,19 +15,14 @@ class PreStitchedTextureMap; typedef enum _TEXTURE_NAME { TN__BLUR__MISC_PUMPKINBLUR, -#ifdef ENABLE_JAVA_GUIS TN__BLUR__MISC_VIGNETTE, // Not currently used -#endif TN__CLAMP__MISC_SHADOW, -#ifdef ENABLE_JAVA_GUIS TN_ACHIEVEMENT_BG, // Not currently used -#endif TN_ART_KZ, TN_ENVIRONMENT_CLOUDS, TN_ENVIRONMENT_RAIN, TN_ENVIRONMENT_SNOW, TN_GUI_GUI, -#ifdef ENABLE_JAVA_GUIS TN_GUI_BACKGROUND, TN_GUI_INVENTORY, TN_GUI_CONTAINER, @@ -38,7 +33,6 @@ typedef enum _TEXTURE_NAME { TN_GUI_CREATIVE_TAB_INVENTORY, TN_GUI_CREATIVE_TAB_ITEM_SEARCH, TN_TITLE_MCLOGO, -#endif TN_GUI_ICONS, TN_ITEM_ARROWS, TN_ITEM_BOAT, From ecc6f0d549bb0142039de266bd2aa8d4c02315b4 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 17:25:06 +0300 Subject: [PATCH 24/29] fix(achievements): restore achievement popup display Was removed by the dev merge --- Minecraft.Client/Player/LocalPlayer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/Player/LocalPlayer.cpp b/Minecraft.Client/Player/LocalPlayer.cpp index 2f8c1911f..4689b25f7 100644 --- a/Minecraft.Client/Player/LocalPlayer.cpp +++ b/Minecraft.Client/Player/LocalPlayer.cpp @@ -709,10 +709,12 @@ void LocalPlayer::awardStat(Stat* stat, byteArray param) { // storage device, so needs a primary player, and the player may not // have been a primary player when they first 'got' the award so let the // award manager figure it out - // if (!minecraft->stats[m_iPad]->hasTaken(ach)) + if (!minecraft->stats[m_iPad]->hasTaken(ach)) { // 4J-PB - Don't display the java popup - // minecraft->achievementPopup->popup(ach); +#ifdef ENABLE_JAVA_GUIS + minecraft->achievementPopup->popup(ach); +#endif // 4J Stu - Added this function in the libraries as some // achievements don't get awarded to all players e.g. Splitscreen From 4c01f7b317e92ee739feb1849bbb304d48282cf0 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 17:41:22 +0300 Subject: [PATCH 25/29] refactor: combine iggy and Java GUI conditionals for trial auto-start --- Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp index d2d2799fd..eb4eb23f6 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp @@ -1806,17 +1806,15 @@ void UIScene_MainMenu::tick() { UIScene::tick(); -#ifndef _ENABLEIGGY +#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS { static int s_mainMenuTickCount = 0; s_mainMenuTickCount++; if(s_mainMenuTickCount % 60 == 1) { fprintf(stderr, "[MM] tick %d\n", s_mainMenuTickCount); fflush(stderr); } if(s_mainMenuTickCount == 90) // ~3 seconds at 30fps { -#ifndef ENABLE_JAVA_GUIS fprintf(stderr, "[Linux] Auto-starting trial world from MainMenu after %d ticks\n", s_mainMenuTickCount); LoadTrial(); -#endif return; } } From 2e1d4bbaca40f450524745caaacdb6151d677659 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 17:46:30 +0300 Subject: [PATCH 26/29] build: prevent enabling both iggy and java GUIs at the same time --- Minecraft.Client/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Minecraft.Client/meson.build b/Minecraft.Client/meson.build index c36051886..bcf1de0b0 100644 --- a/Minecraft.Client/meson.build +++ b/Minecraft.Client/meson.build @@ -77,6 +77,10 @@ if get_option('enable_java_guis') global_cpp_defs += '-DENABLE_JAVA_GUIS' endif +if get_option('enable_shiggy') and get_option('enable_java_guis') + error('You cannot use the Iggy and Java UI at the same time, please choose one.') +endif + client = executable('Minecraft.Client', client_sources + platform_sources + localisation[1], include_directories : include_directories('Platform', 'Platform/Linux/Iggy/include'), From c1955fd208dc88b17213cbd569feaf75155eff5f Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 17:55:35 +0300 Subject: [PATCH 27/29] chore: also add Java GUI conditionals against the intro autoskip unnecessary code that isn't used in any UI-ful case --- Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp | 6 +++--- Minecraft.Client/Platform/Common/UI/UIScene_Intro.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp index ce3b01c1a..f38e12e9e 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp @@ -2,7 +2,7 @@ #include "UI.h" #include "UIScene_Intro.h" -#ifndef _ENABLEIGGY +#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS static int s_introTickCount = 0; #endif @@ -12,7 +12,7 @@ UIScene_Intro::UIScene_Intro(int iPad, void *initData, UILayer *parentLayer) : U initialiseMovie(); m_bIgnoreNavigate = false; m_bAnimationEnded = false; -#ifndef _ENABLEIGGY +#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS s_introTickCount = 0; #endif @@ -171,7 +171,7 @@ void UIScene_Intro::handleGainFocus(bool navBack) } } -#ifndef _ENABLEIGGY +#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS void UIScene_Intro::tick() { // Call base tick first (processes Iggy ticking) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h index 45da2ed2d..28e9479cf 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h @@ -49,7 +49,7 @@ public: virtual void handleTouchInput(unsigned int iPad, S32 x, S32 y, int iId, bool bPressed, bool bRepeat, bool bReleased); #endif -#ifndef _ENABLEIGGY +#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS virtual void tick(); #endif }; From b947bc5c6cfe5a049d142d5245778079deb6b839 Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 18:16:21 +0300 Subject: [PATCH 28/29] fix: incorrect conditionals --- Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp | 6 +++--- Minecraft.Client/Platform/Common/UI/UIScene_Intro.h | 2 +- Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp index f38e12e9e..4e9af013b 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp @@ -2,7 +2,7 @@ #include "UI.h" #include "UIScene_Intro.h" -#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS +#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) static int s_introTickCount = 0; #endif @@ -12,7 +12,7 @@ UIScene_Intro::UIScene_Intro(int iPad, void *initData, UILayer *parentLayer) : U initialiseMovie(); m_bIgnoreNavigate = false; m_bAnimationEnded = false; -#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS +#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) s_introTickCount = 0; #endif @@ -171,7 +171,7 @@ void UIScene_Intro::handleGainFocus(bool navBack) } } -#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS +#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) void UIScene_Intro::tick() { // Call base tick first (processes Iggy ticking) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h index 28e9479cf..f180077c7 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h @@ -49,7 +49,7 @@ public: virtual void handleTouchInput(unsigned int iPad, S32 x, S32 y, int iId, bool bPressed, bool bRepeat, bool bReleased); #endif -#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS +#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) virtual void tick(); #endif }; diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp index eb4eb23f6..42570b990 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp @@ -1806,7 +1806,7 @@ void UIScene_MainMenu::tick() { UIScene::tick(); -#if !defined _ENABLEIGGY || !defined ENABLE_JAVA_GUIS +#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) { static int s_mainMenuTickCount = 0; s_mainMenuTickCount++; From 4937b92b1ee8c42dc4bd2c0f23829bf3663770ef Mon Sep 17 00:00:00 2001 From: Sally Knight Date: Mon, 16 Mar 2026 18:34:06 +0300 Subject: [PATCH 29/29] fix: still skip intro scene in java gui so that the cursor isn't grabbed --- Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp | 6 +++--- Minecraft.Client/Platform/Common/UI/UIScene_Intro.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp index 4e9af013b..ce3b01c1a 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.cpp @@ -2,7 +2,7 @@ #include "UI.h" #include "UIScene_Intro.h" -#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) +#ifndef _ENABLEIGGY static int s_introTickCount = 0; #endif @@ -12,7 +12,7 @@ UIScene_Intro::UIScene_Intro(int iPad, void *initData, UILayer *parentLayer) : U initialiseMovie(); m_bIgnoreNavigate = false; m_bAnimationEnded = false; -#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) +#ifndef _ENABLEIGGY s_introTickCount = 0; #endif @@ -171,7 +171,7 @@ void UIScene_Intro::handleGainFocus(bool navBack) } } -#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) +#ifndef _ENABLEIGGY void UIScene_Intro::tick() { // Call base tick first (processes Iggy ticking) diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h index f180077c7..45da2ed2d 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_Intro.h @@ -49,7 +49,7 @@ public: virtual void handleTouchInput(unsigned int iPad, S32 x, S32 y, int iId, bool bPressed, bool bRepeat, bool bReleased); #endif -#if !defined(_ENABLEIGGY) && !defined(ENABLE_JAVA_GUIS) +#ifndef _ENABLEIGGY virtual void tick(); #endif };