From b941a27b904e872f017cf96217a04925fd41201d Mon Sep 17 00:00:00 2001 From: MrTheShy <49885496+MrTheShy@users.noreply.github.com> Date: Wed, 11 Mar 2026 23:16:31 +0100 Subject: [PATCH 1/4] fix: avoid full rebuild by writing BuildVer.h only when content changes Previously, prebuild.ps1 unconditionally overwrote BuildVer.h on every build using Set-Content, updating its timestamp even when the content was identical. This caused MSBuild to treat all files depending on BuildVer.h as out of date, triggering a full rebuild every time. Fix: compare the new content with the existing file before writing. BuildVer.h is now only written if sha, branch, or dev suffix has actually changed. Also removed the `git restore` call from postbuild.ps1 as it is no longer needed. --- Minecraft.Client/postbuild.ps1 | 6 ++---- Minecraft.Client/prebuild.ps1 | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Minecraft.Client/postbuild.ps1 b/Minecraft.Client/postbuild.ps1 index 8ffc9b98b..6d2bda12b 100644 --- a/Minecraft.Client/postbuild.ps1 +++ b/Minecraft.Client/postbuild.ps1 @@ -36,8 +36,6 @@ foreach ($copy in $copies) { if (Test-Path $src) { # Copy the files using xcopy, forcing overwrite and suppressing errors, and only copying if the source is newer than the destination - xcopy /q /y /i /s /e /d "$src" "$dst" 2>$null + xcopy /q /y /i /s /e /d "$src" "$dst" 2>$null } -} - -git restore "**/BuildVer.h" \ No newline at end of file +} \ No newline at end of file diff --git a/Minecraft.Client/prebuild.ps1 b/Minecraft.Client/prebuild.ps1 index 0acbf023b..99078e9e5 100644 --- a/Minecraft.Client/prebuild.ps1 +++ b/Minecraft.Client/prebuild.ps1 @@ -27,7 +27,7 @@ if (git status --porcelain) { $suffix = "-dev" } -@" +$newContent = @" #pragma once #define VER_PRODUCTBUILD $build @@ -35,4 +35,14 @@ if (git status --porcelain) { #define VER_FILEVERSION_STR_W VER_PRODUCTVERSION_STR_W #define VER_BRANCHVERSION_STR_W L"$ref" #define VER_NETWORK VER_PRODUCTBUILD -"@ | Set-Content "Common/BuildVer.h" +"@ + +$path = "Common/BuildVer.h" +$existing = if (Test-Path $path) { Get-Content $path -Raw } else { "" } + +if ($existing.Trim() -ne $newContent.Trim()) { + $newContent | Set-Content $path + Write-Host "BuildVer.h aggiornato." +} else { + Write-Host "BuildVer.h invariato, skip." +} \ No newline at end of file From bcc8fe25eabc5b1f49cded33f46ed115ff0ae229 Mon Sep 17 00:00:00 2001 From: MrTheShy <49885496+MrTheShy@users.noreply.github.com> Date: Wed, 11 Mar 2026 23:22:13 +0100 Subject: [PATCH 2/4] updated as review requested --- Minecraft.Client/postbuild.ps1 | 4 +++- Minecraft.Client/prebuild.ps1 | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Minecraft.Client/postbuild.ps1 b/Minecraft.Client/postbuild.ps1 index 6d2bda12b..405ca2392 100644 --- a/Minecraft.Client/postbuild.ps1 +++ b/Minecraft.Client/postbuild.ps1 @@ -38,4 +38,6 @@ foreach ($copy in $copies) { # Copy the files using xcopy, forcing overwrite and suppressing errors, and only copying if the source is newer than the destination xcopy /q /y /i /s /e /d "$src" "$dst" 2>$null } -} \ No newline at end of file +} + +git restore "**/BuildVer.h" \ No newline at end of file diff --git a/Minecraft.Client/prebuild.ps1 b/Minecraft.Client/prebuild.ps1 index 99078e9e5..47854ca0d 100644 --- a/Minecraft.Client/prebuild.ps1 +++ b/Minecraft.Client/prebuild.ps1 @@ -42,7 +42,4 @@ $existing = if (Test-Path $path) { Get-Content $path -Raw } else { "" } if ($existing.Trim() -ne $newContent.Trim()) { $newContent | Set-Content $path - Write-Host "BuildVer.h aggiornato." -} else { - Write-Host "BuildVer.h invariato, skip." } \ No newline at end of file From 0edb9f81ed3fc56a21964579abde5e524e8f26b0 Mon Sep 17 00:00:00 2001 From: MrTheShy <49885496+MrTheShy@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:39:26 +0100 Subject: [PATCH 3/4] Refactor safe zone calculations in UI components for consistency Updated the safe zone calculations across multiple UI components to ensure symmetry in split viewports. Removed unnecessary assignments and added comments for clarity. Modified the repositionHud function to include an additional parameter for better handling of HUD positioning in split-screen scenarios. --- .../Common/UI/UIComponent_Tooltips.cpp | 20 +++++++------ Minecraft.Client/Common/UI/UIScene.cpp | 21 +++++++++----- Minecraft.Client/Common/UI/UIScene_HUD.cpp | 28 +++++++++++-------- Minecraft.Client/Common/UI/UIScene_HUD.h | 2 +- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIComponent_Tooltips.cpp b/Minecraft.Client/Common/UI/UIComponent_Tooltips.cpp index 418546b70..4f60de5fd 100644 --- a/Minecraft.Client/Common/UI/UIComponent_Tooltips.cpp +++ b/Minecraft.Client/Common/UI/UIComponent_Tooltips.cpp @@ -93,18 +93,22 @@ void UIComponent_Tooltips::updateSafeZone() case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: - safeBottom = getSafeZoneHalfHeight(); + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: - safeLeft = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); + safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: - safeRight = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: safeTop = getSafeZoneHalfHeight(); @@ -112,22 +116,22 @@ void UIComponent_Tooltips::updateSafeZone() break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: safeTop = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: - safeBottom = getSafeZoneHalfHeight(); + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: - safeBottom = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_FULLSCREEN: default: safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); - safeRight = getSafeZoneHalfWidth(); + break; } setSafeZone(safeTop, safeBottom, safeLeft, safeRight); diff --git a/Minecraft.Client/Common/UI/UIScene.cpp b/Minecraft.Client/Common/UI/UIScene.cpp index 0088f43d4..303897a7f 100644 --- a/Minecraft.Client/Common/UI/UIScene.cpp +++ b/Minecraft.Client/Common/UI/UIScene.cpp @@ -172,15 +172,22 @@ void UIScene::updateSafeZone() { case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: safeTop = getSafeZoneHalfHeight(); + safeLeft = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: - safeBottom = getSafeZoneHalfHeight(); + // safeTop mirrors SPLIT_TOP for visual symmetry. safeBottom omitted. + safeTop = getSafeZoneHalfHeight(); + safeLeft = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: - safeRight = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: safeTop = getSafeZoneHalfHeight(); @@ -188,22 +195,22 @@ void UIScene::updateSafeZone() break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: safeTop = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: - safeBottom = getSafeZoneHalfHeight(); + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: - safeBottom = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_FULLSCREEN: default: safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); - safeRight = getSafeZoneHalfWidth(); + break; } setSafeZone(safeTop, safeBottom, safeLeft, safeRight); diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index 0d8adcb24..213caa8dc 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -65,22 +65,26 @@ void UIScene_HUD::updateSafeZone() case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); - safeRight = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: - safeBottom = getSafeZoneHalfHeight(); + // safeTop mirrors SPLIT_TOP so both players have the same vertical inset + // from their viewport's top edge (split divider), keeping GUI symmetrical. + // safeBottom is intentionally omitted: it would shift m_Hud.y upward in + // ActionScript, placing the hotbar too high relative to SPLIT_TOP. + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); - safeRight = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: - safeLeft = getSafeZoneHalfWidth(); safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); + safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: - safeRight = getSafeZoneHalfWidth(); safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: safeTop = getSafeZoneHalfHeight(); @@ -88,22 +92,22 @@ void UIScene_HUD::updateSafeZone() break; case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: safeTop = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: - safeBottom = getSafeZoneHalfHeight(); + safeTop = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); break; case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: - safeBottom = getSafeZoneHalfHeight(); - safeRight = getSafeZoneHalfWidth(); + safeTop = getSafeZoneHalfHeight(); + break; case C4JRender::VIEWPORT_TYPE_FULLSCREEN: default: safeTop = getSafeZoneHalfHeight(); safeBottom = getSafeZoneHalfHeight(); safeLeft = getSafeZoneHalfWidth(); - safeRight = getSafeZoneHalfWidth(); + break; } setSafeZone(safeTop, safeBottom, safeLeft, safeRight); @@ -734,7 +738,7 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) ); - repositionHud(tileWidth, tileHeight, scale); + repositionHud(tileWidth, tileHeight, scale, needsYTile); m_renderWidth = tileWidth; m_renderHeight = tileHeight; @@ -805,7 +809,7 @@ void UIScene_HUD::handleTimerComplete(int id) //setVisible(anyVisible); } -void UIScene_HUD::repositionHud(S32 tileWidth, S32 tileHeight, F32 scale) +void UIScene_HUD::repositionHud(S32 tileWidth, S32 tileHeight, F32 scale, bool needsYTile) { if(!m_bSplitscreen) return; diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.h b/Minecraft.Client/Common/UI/UIScene_HUD.h index 569b52349..04468c8ec 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.h +++ b/Minecraft.Client/Common/UI/UIScene_HUD.h @@ -176,5 +176,5 @@ class UIScene_HUD : public UIScene, public IUIScene_HUD #endif private: - void repositionHud(S32 tileWidth, S32 tileHeight, F32 scale); + void repositionHud(S32 tileWidth, S32 tileHeight, F32 scale, bool needsYTile); }; From 300825b18c24e386ef24192a50d8b997f6454a2e Mon Sep 17 00:00:00 2001 From: MrTheShy <49885496+MrTheShy@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:52:23 +0100 Subject: [PATCH 4/4] Gui.cpp: fix F3 debug overlay in splitscreen + minor perf cleanup The F3 debug screen was badly broken in splitscreen: it used the GUI coordinate space which gets distorted by the splitscreen scaling, so text appeared stretched, misaligned or completely off-screen depending on the viewport layout. Fixed by setting up a dedicated projection matrix using physical pixel coordinates (g_rScreenWidth / g_rScreenHeight) each time the overlay is drawn, completely decoupled from whatever transform the HUD is using. The viewport dimensions are now computed per screen section so the ortho projection matches the actual pixel area of each player's quadrant. Version and branch strings are only shown for player 0 (iPad == 0) to avoid repeating them across every splitscreen pane. Also removed a few redundant calculations that were being done twice in the same frame (atan for xRot, health halves, air supply scaled value). These are minor and have negligible real-world impact; more substantial per-frame caching work (safe zone calculations etc.) will follow in a separate commit. --- Minecraft.Client/Gui.cpp | 402 +++++++++++++++++++-------------------- 1 file changed, 195 insertions(+), 207 deletions(-) diff --git a/Minecraft.Client/Gui.cpp b/Minecraft.Client/Gui.cpp index 43b41998b..f0d44319a 100644 --- a/Minecraft.Client/Gui.cpp +++ b/Minecraft.Client/Gui.cpp @@ -443,7 +443,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) double maxHealth = minecraft->localplayers[iPad]->getAttribute(SharedMonsterAttributes.MAX_HEALTH); double totalAbsorption = minecraft->localplayers[iPad]->getAbsorptionAmount(); - int numHealthRows = Mth.ceil((maxHealth + totalAbsorption) / 2 / (float) NUM_HEARTS_PER_ROW); + const double healthHalves = (maxHealth + totalAbsorption) / 2.0; + int numHealthRows = Mth.ceil(healthHalves / (float) NUM_HEARTS_PER_ROW); int healthRowHeight = Math.max(10 - (numHealthRows - 2), 3); int yLine2 = yLine1 - (numHealthRows - 1) * healthRowHeight - 10; absorption = totalAbsorption; @@ -469,7 +470,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) } //minecraft.profiler.popPush("health"); - for (int i = Mth.ceil((maxHealth + totalAbsorption) / 2) - 1; i >= 0; i--) + for (int i = (int)Mth.ceil(healthHalves) - 1; i >= 0; i--) { int healthTexBaseX = 16; if (minecraft.player.hasEffect(MobEffect.poison)) @@ -607,8 +608,11 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // render air bubbles if (minecraft->player->isUnderLiquid(Material::water)) { - int count = (int) ceil((minecraft->player->getAirSupply() - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY); - int extra = (int) ceil((minecraft->player->getAirSupply()) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count; + const int airSupply = minecraft->player->getAirSupply(); + const float airScale = 10.0f / Player::TOTAL_AIR_SUPPLY; + const float airSupplyScaled = airSupply * airScale; + int count = (int) ceil((airSupply - 2) * airScale); + int extra = (int) ceil(airSupplyScaled) - count; for (int i = 0; i < count + extra; i++) { // Air bubbles @@ -725,7 +729,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) Lighting::turnOn(); glRotatef(-45 - 90, 0, 1, 0); - glRotatef(-(float) atan(yd / 40.0f ) * 20, 1, 0, 0); + const float xRotAngle = -(float) atan(yd / 40.0f) * 20; + glRotatef(xRotAngle, 1, 0, 0); float bodyRot = (minecraft->player->yBodyRotO + (minecraft->player->yBodyRot - minecraft->player->yBodyRotO)); // Fixed rotation angle of degrees, adjusted by bodyRot to negate the rotation that occurs in the renderer // bodyRot in the rotation below is a simplification of "180 - (180 - bodyRot)" where the first 180 is EntityRenderDispatcher::instance->playerRotY that we set below @@ -736,7 +741,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // Set head rotation to body rotation to make head static minecraft->player->yRot = bodyRot; minecraft->player->yRotO = minecraft->player->yRot; - minecraft->player->xRot = -(float) atan(yd / 40.0f) * 20; + minecraft->player->xRot = xRotAngle; minecraft->player->onFire = 0; minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE, false); @@ -849,207 +854,6 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // font.draw(str, x + 1, y, 0xffffff); // } -#ifndef _FINAL_BUILD - MemSect(31); - - // temporarily render overlay at all times so version is more obvious in bug reports - // we can turn this off once things stabilize - if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr) - { - const int debugLeft = 1; - const int debugTop = 1; - const float maxContentWidth = 1200.f; - const float maxContentHeight = 420.f; - float scale = static_cast(screenWidth - debugLeft - 8) / maxContentWidth; - float scaleV = static_cast(screenHeight - debugTop - 80) / maxContentHeight; - if (scaleV < scale) scale = scaleV; - if (scale > 1.f) scale = 1.f; - if (scale < 0.5f) scale = 0.5f; - glPushMatrix(); - glTranslatef(static_cast(debugLeft), static_cast(debugTop), 0.f); - glScalef(scale, scale, 1.f); - glTranslatef(static_cast(-debugLeft), static_cast(-debugTop), 0.f); - - vector lines; - - lines.push_back(ClientConstants::VERSION_STRING); - lines.push_back(ClientConstants::BRANCH_STRING); - if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr) - { - lines.push_back(minecraft->fpsString); - lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); // Could maybe use entity::shouldRender to work out how many are rendered but thats like expensive - // TODO Add server information with packet counts - once multiplayer is more stable - int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance); - // Calculate the chunk sections using 16 * (2n + 1)^2 - lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance)); - lines.push_back(minecraft->gatherStats4()); // Chunk Cache - - // Dimension - wstring dimension = L"unknown"; - switch (minecraft->player->dimension) - { - case -1: - dimension = L"minecraft:the_nether"; - break; - case 0: - dimension = L"minecraft:overworld"; - break; - case 1: - dimension = L"minecraft:the_end"; - break; - } - lines.push_back(dimension); - - lines.push_back(L""); // Spacer - - // Players block pos - int xBlockPos = Mth::floor(minecraft->player->x); - int yBlockPos = Mth::floor(minecraft->player->y); - int zBlockPos = Mth::floor(minecraft->player->z); - - // Chunk player is in - int xChunkPos = xBlockPos >> 4; - int yChunkPos = yBlockPos >> 4; - int zChunkPos = zBlockPos >> 4; - - // Players offset within the chunk - int xChunkOffset = xBlockPos & 15; - int yChunkOffset = yBlockPos & 15; - int zChunkOffset = zBlockPos & 15; - - // Format the position like java with limited decumal places - WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999) - swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z); - - lines.push_back(L"XYZ: " + std::wstring(posString)); - lines.push_back(L"Block: " + std::to_wstring(static_cast(xBlockPos)) + L" " + std::to_wstring(static_cast(yBlockPos)) + L" " + std::to_wstring(static_cast(zBlockPos))); - lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos)); - - // Wrap the yRot to 360 then adjust to (-180 to 180) range to match java - float yRotDisplay = fmod(minecraft->player->yRot, 360.0f); - if (yRotDisplay > 180.0f) - { - yRotDisplay -= 360.0f; - } - if (yRotDisplay < -180.0f) - { - yRotDisplay += 360.0f; - } - // Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition - WCHAR angleString[16]; - swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot); - - // Work out the named direction - int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3; - wstring cardinalDirection; - switch (direction) - { - case 0: - cardinalDirection = L"south"; - break; - case 1: - cardinalDirection = L"west"; - break; - case 2: - cardinalDirection = L"north"; - break; - case 3: - cardinalDirection = L"east"; - break; - } - - lines.push_back(L"Facing: " + cardinalDirection + L" (" + angleString + L")"); - - // We have to limit y to 256 as we don't get any information past that - if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos)) - { - LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos); - if (chunkAt != NULL) - { - int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset); - int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset); - int maxLight = fmax(skyLight, blockLight); - lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)"); - - lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset))); - - Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource()); - lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")"); - - lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")"); - } - } - - // This is all LCE only stuff, it was never on java - lines.push_back(L""); // Spacer - lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed())); - lines.push_back(minecraft->gatherStats1()); // Time to autosave - lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats() - lines.push_back(minecraft->gatherStats3()); // RTT - } - -#ifdef _DEBUG // Only show terrain features in debug builds not release - // TERRAIN FEATURES - if (minecraft->level->dimension->id == 0) - { - wstring wfeature[eTerrainFeature_Count]; - - wfeature[eTerrainFeature_Stronghold] = L"Stronghold: "; - wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: "; - wfeature[eTerrainFeature_Village] = L"Village: "; - wfeature[eTerrainFeature_Ravine] = L"Ravine: "; - - float maxW = static_cast(screenWidth - debugLeft - 8) / scale; - float maxWForContent = maxW - static_cast(font->width(L"...")); - bool truncated[eTerrainFeature_Count] = {}; - - for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++) - { - FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i]; - int type = pFeatureData->eTerrainFeature; - if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) - { - continue; - } - if (truncated[type]) - { - continue; - } - - wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] "; - if (font->width(wfeature[type] + itemInfo) <= maxWForContent) - { - wfeature[type] += itemInfo; - } - else - { - wfeature[type] += L"..."; - truncated[type] = true; - } - } - - lines.push_back(L""); // Add a spacer line - for (int i = eTerrainFeature_Stronghold; i <= static_cast(eTerrainFeature_Ravine); i++) - { - lines.push_back(wfeature[i]); - } - lines.push_back(L""); - } -#endif - - // Loop through the lines and draw them all on screen - int yPos = debugTop; - for (const auto &line : lines) - { - drawString(font, line, debugLeft, yPos, 0xffffff); - yPos += 10; - } - - glPopMatrix(); - } - MemSect(0); -#endif - lastTickA = a; // 4J Stu - This is now displayed in a xui scene #if 0 @@ -1203,6 +1007,190 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) glPopMatrix(); } +#ifndef _FINAL_BUILD + MemSect(31); + if (true) + { + // Real window dimensions updated on every WM_SIZE — always current + extern int g_rScreenWidth; + extern int g_rScreenHeight; + + // Set up a fresh projection using physical pixel coordinates so the debug + // text is never distorted regardless of aspect ratio, splitscreen layout, + // or menu state. 1 coordinate unit = 1 physical pixel. + // Compute the actual viewport dimensions for this player's screen section. + // glOrtho must match the viewport exactly for 1 unit = 1 physical pixel. + int vpW = g_rScreenWidth; + int vpH = g_rScreenHeight; + switch (minecraft->player->m_iScreenSection) + { + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + vpH /= 2; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: + vpW /= 2; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + vpW /= 2; + vpH /= 2; + break; + default: // VIEWPORT_TYPE_FULLSCREEN + break; + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, vpW, vpH, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + // Font was designed for guiScale px/unit; scale up so characters appear + // at the same physical size as the rest of the HUD at 0.5x. + const float fontScale = static_cast(guiScale) * 1.0f; + const int debugLeft = 1; + const int debugTop = 1; + + glTranslatef(static_cast(debugLeft), static_cast(debugTop), 0.f); + glScalef(fontScale, fontScale, 1.f); + glTranslatef(static_cast(-debugLeft), static_cast(-debugTop), 0.f); + + vector lines; + + // Only show version/branch for player 0 to avoid cluttering each splitscreen viewport + if (iPad == 0) + { + lines.push_back(ClientConstants::VERSION_STRING); + lines.push_back(ClientConstants::BRANCH_STRING); + } + if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr) + { + lines.push_back(minecraft->fpsString); + lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); + int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance); + lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance)); + lines.push_back(minecraft->gatherStats4()); + + wstring dimension = L"unknown"; + switch (minecraft->player->dimension) + { + case -1: dimension = L"minecraft:the_nether"; break; + case 0: dimension = L"minecraft:overworld"; break; + case 1: dimension = L"minecraft:the_end"; break; + } + lines.push_back(dimension); + lines.push_back(L""); + + int xBlockPos = Mth::floor(minecraft->player->x); + int yBlockPos = Mth::floor(minecraft->player->y); + int zBlockPos = Mth::floor(minecraft->player->z); + int xChunkPos = xBlockPos >> 4; + int yChunkPos = yBlockPos >> 4; + int zChunkPos = zBlockPos >> 4; + int xChunkOffset = xBlockPos & 15; + int yChunkOffset = yBlockPos & 15; + int zChunkOffset = zBlockPos & 15; + + WCHAR posString[44]; + swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z); + + lines.push_back(L"XYZ: " + std::wstring(posString)); + lines.push_back(L"Block: " + std::to_wstring(xBlockPos) + L" " + std::to_wstring(yBlockPos) + L" " + std::to_wstring(zBlockPos)); + lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos)); + + float yRotDisplay = fmod(minecraft->player->yRot, 360.0f); + if (yRotDisplay > 180.0f) yRotDisplay -= 360.0f; + if (yRotDisplay < -180.0f) yRotDisplay += 360.0f; + WCHAR angleString[16]; + swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot); + + int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3; + const wchar_t* cardinals[] = { L"south", L"west", L"north", L"east" }; + lines.push_back(L"Facing: " + std::wstring(cardinals[direction]) + L" (" + angleString + L")"); + + if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos)) + { + LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos); + if (chunkAt != NULL) + { + int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset); + int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset); + int maxLight = fmax(skyLight, blockLight); + lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)"); + lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset))); + Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource()); + lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")"); + lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")"); + } + } + + lines.push_back(L""); + lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed())); + lines.push_back(minecraft->gatherStats1()); + lines.push_back(minecraft->gatherStats2()); + lines.push_back(minecraft->gatherStats3()); + } + +#ifdef _DEBUG + if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr && minecraft->level->dimension->id == 0) + { + wstring wfeature[eTerrainFeature_Count]; + wfeature[eTerrainFeature_Stronghold] = L"Stronghold: "; + wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: "; + wfeature[eTerrainFeature_Village] = L"Village: "; + wfeature[eTerrainFeature_Ravine] = L"Ravine: "; + + // maxW in font units: physical width divided by font scale + float maxW = (static_cast(g_rScreenWidth) - debugLeft - 8) / fontScale; + float maxWForContent = maxW - static_cast(font->width(L"...")); + bool truncated[eTerrainFeature_Count] = {}; + + for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++) + { + FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i]; + int type = pFeatureData->eTerrainFeature; + if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) continue; + if (truncated[type]) continue; + wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] "; + if (font->width(wfeature[type] + itemInfo) <= maxWForContent) + wfeature[type] += itemInfo; + else + { + wfeature[type] += L"..."; + truncated[type] = true; + } + } + + lines.push_back(L""); + for (int i = eTerrainFeature_Stronghold; i <= static_cast(eTerrainFeature_Ravine); i++) + lines.push_back(wfeature[i]); + lines.push_back(L""); + } +#endif + + int yPos = debugTop; + for (const auto &line : lines) + { + drawString(font, line, debugLeft, yPos, 0xffffff); + yPos += 10; + } + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + MemSect(0); +#endif + glColor4f(1, 1, 1, 1); glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST);