mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCE-Revelations.git
synced 2026-05-23 07:56:33 +00:00
---
Minecraft.Client/ClientConnection.cpp
Purpose: Propagate hardcore flag through network level creation
- handleLogin() (2 sites): Changed MultiPlayerLevel constructor calls from hardcoded false for the
hardcore parameter to packet->m_isHardcore, so the client-side level correctly knows it's hardcore
when joining a server.
- handleRespawn(): Same change - when creating a new dimension level on respawn, uses
packet->m_isHardcore instead of querying minecraft->level->getLevelData()->isHardcore() (which could
be stale/wrong).
---
Minecraft.Client/Common/App_Defines.h
Purpose: Define bitmask for hardcore host option
- Added GAME_HOST_OPTION_BITMASK_HARDCORE (0x40000000) - a new bit in the host options bitfield to
store whether the game is hardcore.
---
Minecraft.Client/Common/App_enums.h
Purpose: Add hardcore enum value
- Added eGameHostOption_Hardcore to the eGameHostOption enum so code can get/set the hardcore flag
via SetGameHostOption/GetGameHostOption.
---
Minecraft.Client/Common/Consoles_App.cpp
Purpose: Implement hardcore get/set in host options bitfield
- SetGameHostOption(): Added case eGameHostOption_Hardcore - sets or clears the
GAME_HOST_OPTION_BITMASK_HARDCORE bit.
- GetGameHostOption(): Added case eGameHostOption_Hardcore - returns 1 if the hardcore bit is set, 0
otherwise.
---
Minecraft.Client/Common/Consoles_App.h
Purpose: Store save folder name for hardcore world deletion
- Added SetCurrentSaveFolderName() and GetCurrentSaveFolderName() public methods.
- Added wstring m_currentSaveFolderName private member - stores the save folder name so the hardcore
death handler can find and delete the world.
---
Minecraft.Client/Common/UI/IUIScene_PauseMenu.cpp
Purpose: Delete hardcore world's save data on exit
- Added Win64_DeleteSaveDirectory() - a recursive directory deletion helper (Windows64 only).
- In _ExitWorld(): Before the server is torn down, captures whether this is a hardcore death exit
(getDeleteWorldOnExit()). Tries 3 sources for the save folder name: app storage, StorageManager, and
MinecraftServer.
- After the server fully stops, if shouldDeleteHardcoreWorld is true, deletes the entire
Windows64\GameHDD\<savefolder> directory.
---
Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp
Purpose: Hardcore difficulty slider in Create World menu
- Added file-scope s_bHardcore flag to track when the slider is at position 4 (Hardcore).
- Constructor: Extended difficulty slider range from 0-3 to 0-4, resets s_bHardcore to false.
- handleSliderMove(): When slider value >= 4, sets s_bHardcore = true, stores actual difficulty as 3
(Hard), and displays "Hardcore" label. Otherwise behaves normally.
- CreateGame(): Clears the save folder name (new world), and sets eGameHostOption_Hardcore based on
s_bHardcore.
- Minor: Changed RequestErrorMessage to RequestAlertMessage for a content restriction dialog.
---
Minecraft.Client/Common/UI/UIScene_DeathMenu.cpp
Purpose: Hardcore death screen behavior (Iggy UI)
- Constructor: Checks if current level is hardcore. If so, shows IDS_HARDCORE_DEATH_MESSAGE on the
respawn button and hides it. Otherwise shows normal "Respawn" button.
- handlePress() - Respawn: Added safeguard - if hardcore, blocks respawn entirely.
- handlePress() - Exit Game: If hardcore and host, skips save dialog, disables save-on-exit, enables
delete-world-on-exit, and triggers immediate world exit.
---
Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp
Purpose: Show "Difficulty: Hardcore" in Load World menu + persist hardcore through game launch
- Static array: Expanded m_iDifficultyTitleSettingA from 4 to 5 entries, added IDS_GAMEMODE_HARDCORE
at index 4.
- Constructor: Initializes m_bHardcore = false. In Windows64 block: sets up thumbnail name from save
details, and reads isHardcore from params->saveDetails. If hardcore, immediately initializes the
difficulty slider to show "Hardcore" locked at position 4.
- tick(): When host options are read (bHostOptionsRead block), also reads the hardcore flag and
re-initializes the slider if needed (for console path).
- handleSliderMove(): If m_bHardcore, locks the slider at position 4 (prevents changing difficulty).
- StartGameFromSave(): Stores the save folder name in app for later hardcore deletion. Sets
eGameHostOption_Hardcore from m_bHardcore.
---
Minecraft.Client/Common/UI/UIScene_LoadMenu.h
Purpose: Declare hardcore member
- Expanded m_iDifficultyTitleSettingA from [4] to [5].
- Added bool m_bHardcore private member.
---
Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
Purpose: Read hardcore flag from level.dat when building the save list
- ReadLevelNameFromSaveFile(): Added optional bool *outHardcore parameter. Inside the NBT Data
compound tag parsing, if outHardcore is non-null, reads dataTag->getBoolean(L"hardcore").
- Save enumeration block (Windows64): Passes &saveHardcore to ReadLevelNameFromSaveFile and stores
the result in m_saveDetails[i].isHardcore.
---
Minecraft.Client/Common/UI/UIStructs.h
Purpose: Add isHardcore to save list details struct
- Added bool isHardcore field to _SaveListDetails struct.
- Initialized to false in the constructor.
---
Minecraft.Client/Common/XUI/XUI_Death.cpp
Purpose: Hardcore death screen behavior (XUI/Xbox UI)
- Mirror of the Iggy UIScene_DeathMenu.cpp changes but for the XUI rendering path.
- OnInit(): Checks isHardcore(), hides respawn button and shows death message if true.
- OnNotifyPressEx() - Exit Game: If hardcore and host, skips save, flags world for deletion, exits
immediately.
- OnNotifyPressEx() - Respawn: Safeguard to block respawn in hardcore.
---
Minecraft.Client/Gui.cpp
Purpose: Syntax fix
- Fixed lines.push_back(L"" → lines.push_back(L"") - missing closing quote/paren in debug terrain
feature display.
---
Minecraft.Client/MinecraftServer.cpp
Purpose: Server-side hardcore support
- Constructor: Initializes m_deleteWorldOnExit = false.
- loadLevel(): Captures the save folder name from StorageManager into m_saveFolderName for later use
in hardcore world deletion.
- isHardcore(): Changed from always returning false to returning
app.GetGameHostOption(eGameHostOption_Hardcore) > 0 - this is the key change that makes the server
actually report hardcore mode.
---
Minecraft.Client/MinecraftServer.h
Purpose: Declare hardcore-related members
- Added bool m_deleteWorldOnExit and wstring m_saveFolderName private members.
- Added setDeleteWorldOnExit(), getDeleteWorldOnExit(), and getSaveFolderName() public methods.
---
Minecraft.Client/PlayerConnection.h
Purpose: Thread-safety fix for kicked flag
- Changed m_bWasKicked from bool to std::atomic<bool> (initialized with {false}).
- Changed setWasKicked()/getWasKicked() to use .store()/.load() - fixes a race condition where the
kicked flag is set on one thread and read on another.
---
Minecraft.Client/PlayerList.cpp
Purpose: Hardcore multiplayer - ban, respawn as Adventure, thread-safe bans
- Constructor/Destructor: Added InitializeCriticalSection/DeleteCriticalSection for m_banCS.
- placeNewPlayer(): Passes isHardcore() flag to the LoginPacket constructor so clients joining know
it's hardcore.
- respawn(): After respawn in hardcore, forces the player into Adventure mode (spectate-like: can
look around but not interact). Sends GameEventPacket to sync client.
- respawn() and toggleDimension() (2 sites): Pass isHardcore() to RespawnPacket constructor.
- isXuidBanned(): Wrapped m_bannedXuids iteration with EnterCriticalSection/LeaveCriticalSection for
thread safety.
- banXuid() (new): Thread-safe method to add a player's XUID to the ban list - used when a player
dies in hardcore multiplayer.
---
Minecraft.Client/PlayerList.h
Purpose: Declare ban-related additions
- Added CRITICAL_SECTION m_banCS to protect m_bannedXuids.
- Added void banXuid(PlayerUID xuid) public method.
---
Minecraft.Client/SelectWorldScreen.cpp
Purpose: Show [Hardcore] badge in Java-style world list
- In renderItem(): If levelSummary->isHardcore(), appends [Hardcore] to the world name display.
---
Minecraft.Client/ServerPlayer.cpp
Purpose: Hardcore death behavior on server
- die(): If the level is hardcore, switches the dead player to Adventure mode (so they can't
interact if somehow respawned).
- Minor: Two comment lines changed // → /// (no functional change).
---
Minecraft.Client/Windows64Media/strings.h
Purpose: String IDs for hardcore UI text
- Added 8 new string IDs (2286-2293): IDS_GAMEMODE_HARDCORE, IDS_HARDCORE, IDS_HARDCORE_TOOLTIP,
IDS_HARDCORE_WARNING_TITLE, IDS_HARDCORE_WARNING_TEXT, IDS_HARDCORE_DEATH_MESSAGE,
IDS_LABEL_HARDCORE, IDS_GAMEOPTION_HARDCORE.
---
Minecraft.World/ConsoleSaveFileOriginal.cpp
Purpose: Capture save folder name after first save (for new worlds)
- SaveSaveDataCallback() (Windows64 only): After a successful save, if the app doesn't yet know the
save folder name, attempts to capture it via StorageManager or by scanning Windows64\GameHDD\ for
the newest folder. This handles the case where a newly-created hardcore world hasn't been saved yet
when the folder name is needed.
---
Minecraft.World/DisconnectPacket.h
Purpose: Hardcore disconnect reason
- Added eDisconnect_HardcoreDeath to the disconnect reason enum - used when kicking a player who
died in hardcore multiplayer.
---
Minecraft.World/LoginPacket.cpp & LoginPacket.h
Purpose: Serialize hardcore flag in login packet
- Added bool m_isHardcore member, initialized to false in both constructors.
- Server→Client constructor now accepts bool isHardcore = false parameter.
- read(): Reads m_isHardcore from the stream.
- write(): Writes m_isHardcore to the stream.
- getEstimatedSize(): Added sizeof(bool) for the new field.
---
Minecraft.World/RespawnPacket.cpp & RespawnPacket.h
Purpose: Serialize hardcore flag in respawn packet
- Added bool m_isHardcore member, initialized to false.
- Constructor now accepts bool isHardcore = false parameter.
- read()/write(): Serialize m_isHardcore via readBoolean()/writeBoolean().
- getEstimatedSize(): Changed from 13 to 14 bytes to account for the new boolean.
1712 lines
55 KiB
C++
1712 lines
55 KiB
C++
#include "stdafx.h"
|
|
#include "Gui.h"
|
|
#include "ItemRenderer.h"
|
|
#include "GameRenderer.h"
|
|
#include "Options.h"
|
|
#include "MultiplayerLocalPlayer.h"
|
|
#include "Textures.h"
|
|
#include "TextureAtlas.h"
|
|
#include "GameMode.h"
|
|
#include "Lighting.h"
|
|
#include "ChatScreen.h"
|
|
#include "MultiPlayerLevel.h"
|
|
#include "..\Minecraft.World\JavaMath.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.effect.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.food.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.h"
|
|
#include "..\Minecraft.World\LevelData.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
|
|
#include "..\Minecraft.World\System.h"
|
|
#include "..\Minecraft.World\Language.h"
|
|
#include "EntityRenderDispatcher.h"
|
|
#include "..\Minecraft.World\Dimension.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h"
|
|
#include "EnderDragonRenderer.h"
|
|
#include "..\Minecraft.World\net.minecraft.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.h"
|
|
#include "..\Minecraft.World\LevelChunk.h"
|
|
#include "..\Minecraft.World\Biome.h"
|
|
#include <Common/UI/UI.h>
|
|
|
|
ResourceLocation Gui::PUMPKIN_BLUR_LOCATION = ResourceLocation(TN__BLUR__MISC_PUMPKINBLUR);
|
|
|
|
#define RENDER_HUD 0
|
|
//#ifndef _XBOX
|
|
//#undef RENDER_HUD
|
|
//#define RENDER_HUD 1
|
|
//#endif
|
|
|
|
float Gui::currentGuiBlendFactor = 1.0f; // 4J added
|
|
float Gui::currentGuiScaleFactor = 1.0f; // 4J added
|
|
ItemRenderer *Gui::itemRenderer = new ItemRenderer();
|
|
|
|
Gui::Gui(Minecraft *minecraft)
|
|
{
|
|
// 4J - initialisers added
|
|
random = new Random();
|
|
tickCount = 0;
|
|
overlayMessageTime = 0;
|
|
animateOverlayMessageColor = false;
|
|
progress = 0.0f;
|
|
tbr = 1.0f;
|
|
fAlphaIncrementPerCent=255.0f/100.0f;
|
|
|
|
this->minecraft = minecraft;
|
|
|
|
lastTickA = 0.0f;
|
|
}
|
|
|
|
void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
|
{
|
|
// 4J Stu - I have copied this code for XUI_BaseScene. If/when it gets changed it should be broken out
|
|
// 4J - altered to force full screen mode to 3X scaling, and any split screen modes to 2X scaling. This is so that the further scaling by 0.5 that
|
|
// happens in split screen modes results in a final scaling of 1 rather than 1.5.
|
|
|
|
if (minecraft->player == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int splitYOffset;// = 20; // This offset is applied when doing the 2X scaling above to move the gui out of the way of the tool tips
|
|
int guiScale;// = ( minecraft->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN ? 3 : 2 );
|
|
int iPad=minecraft->player->GetXboxPad();
|
|
int iWidthOffset=0,iHeightOffset=0; // used to get the interface looking right on a 2 player split screen game
|
|
|
|
// 4J-PB - selected the gui scale based on the slider settings
|
|
if(minecraft->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN)
|
|
{
|
|
guiScale=app.GetGameSettings(iPad,eGameSetting_UISize) + 2;
|
|
}
|
|
else
|
|
{
|
|
guiScale=app.GetGameSettings(iPad,eGameSetting_UISizeSplitscreen) + 2;
|
|
}
|
|
|
|
|
|
ScreenSizeCalculator ssc(minecraft->options, minecraft->width, minecraft->height, guiScale );
|
|
int screenWidth = ssc.getWidth();
|
|
int screenHeight = ssc.getHeight();
|
|
int iSafezoneXHalf=0,iSafezoneYHalf=0,iSafezoneTopYHalf=0;
|
|
int iTooltipsYOffset=0;
|
|
int quickSelectWidth=182;
|
|
int quickSelectHeight=22;
|
|
float fScaleFactorWidth=1.0f,fScaleFactorHeight=1.0f;
|
|
bool bTwoPlayerSplitscreen=false;
|
|
currentGuiScaleFactor = static_cast<float>(guiScale); // Keep static copy of scale so we know how gui coordinates map to physical pixels - this is also affected by the viewport
|
|
|
|
switch(guiScale)
|
|
{
|
|
case 3:
|
|
splitYOffset = 0;
|
|
break;
|
|
case 4:
|
|
splitYOffset = -5;
|
|
break;
|
|
default: // 2
|
|
splitYOffset = 10;
|
|
break;
|
|
}
|
|
|
|
// Check which screen section this player is in
|
|
switch(minecraft->player->m_iScreenSection)
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
|
|
// single player
|
|
iSafezoneXHalf = screenWidth/20; // 5%
|
|
iSafezoneYHalf = screenHeight/20; // 5%
|
|
iSafezoneTopYHalf = iSafezoneYHalf;
|
|
iTooltipsYOffset=40+splitYOffset;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
|
iSafezoneXHalf = screenWidth/10; // 5% (need to treat the whole screen is 2x this screen)
|
|
iSafezoneYHalf = splitYOffset;
|
|
iSafezoneTopYHalf = screenHeight/10;
|
|
fScaleFactorWidth=0.5f;
|
|
iWidthOffset=static_cast<int>((float)screenWidth * (1.0f - fScaleFactorWidth));
|
|
iTooltipsYOffset=44;
|
|
bTwoPlayerSplitscreen=true;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
|
iSafezoneXHalf = screenWidth/10; // 5% (need to treat the whole screen is 2x this screen)
|
|
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
|
|
iSafezoneTopYHalf = 0;
|
|
fScaleFactorWidth=0.5f;
|
|
iWidthOffset=static_cast<int>((float)screenWidth * (1.0f - fScaleFactorWidth));
|
|
iTooltipsYOffset=44;
|
|
bTwoPlayerSplitscreen=true;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
|
|
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
|
|
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
|
|
iSafezoneTopYHalf = screenHeight/10;
|
|
fScaleFactorHeight=0.5f;
|
|
iHeightOffset=screenHeight;
|
|
iTooltipsYOffset=44;
|
|
bTwoPlayerSplitscreen=true;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
|
|
iSafezoneXHalf = 0;
|
|
iSafezoneYHalf = splitYOffset + screenHeight/10;// 5% (need to treat the whole screen is 2x this screen)
|
|
iSafezoneTopYHalf = splitYOffset + screenHeight/10;
|
|
fScaleFactorHeight=0.5f;
|
|
iHeightOffset=screenHeight;
|
|
iTooltipsYOffset=44;
|
|
bTwoPlayerSplitscreen=true;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
|
|
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
|
|
iSafezoneYHalf = splitYOffset;
|
|
iSafezoneTopYHalf = screenHeight/10;
|
|
iTooltipsYOffset=44;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
|
|
iSafezoneXHalf = 0;
|
|
iSafezoneYHalf = splitYOffset; // 5%
|
|
iSafezoneTopYHalf = screenHeight/10;
|
|
iTooltipsYOffset=44;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
|
|
iSafezoneXHalf = screenWidth/10; // 5% (the whole screen is 2x this screen)
|
|
iSafezoneYHalf = splitYOffset + screenHeight/10; // 5% (the whole screen is 2x this screen)
|
|
iSafezoneTopYHalf = 0;
|
|
iTooltipsYOffset=44;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
|
|
iSafezoneXHalf = 0;
|
|
iSafezoneYHalf = splitYOffset + screenHeight/10; // 5% (the whole screen is 2x this screen)
|
|
iSafezoneTopYHalf = 0;
|
|
iTooltipsYOffset=44;
|
|
currentGuiScaleFactor *= 0.5f;
|
|
break;
|
|
|
|
}
|
|
|
|
// 4J-PB - turn off the slot display if a xui menu is up, or if we're autosaving
|
|
bool bDisplayGui=!ui.GetMenuDisplayed(iPad) && !(app.GetXuiAction(iPad)==eAppAction_AutosaveSaveGameCapturedThumbnail);
|
|
|
|
// if tooltips are off, set the y offset to zero
|
|
if(app.GetGameSettings(iPad,eGameSetting_Tooltips)==0 && bDisplayGui)
|
|
{
|
|
switch(minecraft->player->m_iScreenSection)
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
|
|
iTooltipsYOffset=screenHeight/10;
|
|
break;
|
|
default:
|
|
//iTooltipsYOffset=screenHeight/10;
|
|
switch(guiScale)
|
|
{
|
|
case 3:
|
|
iTooltipsYOffset=28;//screenHeight/10;
|
|
break;
|
|
case 4:
|
|
iTooltipsYOffset=28;//screenHeight/10;
|
|
break;
|
|
default: // 2
|
|
iTooltipsYOffset=14;//screenHeight/10;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 4J-PB - Turn off interface if eGameSetting_DisplayHUD is off - for screen shots/videos.
|
|
if ( app.GetGameSettings(iPad,eGameSetting_DisplayHUD)==0 )
|
|
{
|
|
bDisplayGui = false;
|
|
}
|
|
|
|
Font *font = minecraft->font;
|
|
|
|
|
|
minecraft->gameRenderer->setupGuiScreen(guiScale);
|
|
|
|
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 4J - added - this did actually get set in renderVignette but that code is currently commented out
|
|
|
|
if (Minecraft::useFancyGraphics())
|
|
{
|
|
renderVignette(minecraft->player->getBrightness(a), screenWidth, screenHeight);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// Display the pumpkin screen effect
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
shared_ptr<ItemInstance> headGear = minecraft->player->inventory->getArmor(3);
|
|
|
|
// 4J-PB - changing this to be per player
|
|
//if (!minecraft->options->thirdPersonView && headGear != NULL && headGear->id == Tile::pumpkin_Id) renderPumpkin(screenWidth, screenHeight);
|
|
if ((minecraft->player->ThirdPersonView()==0) && headGear != NULL && headGear->id == Tile::pumpkin_Id) renderPumpkin(screenWidth, screenHeight);
|
|
if (!minecraft->player->hasEffect(MobEffect::confusion))
|
|
{
|
|
float pt = minecraft->player->oPortalTime + (minecraft->player->portalTime - minecraft->player->oPortalTime) * a;
|
|
if (pt > 0)
|
|
{
|
|
renderTp(pt, screenWidth, screenHeight);
|
|
}
|
|
}
|
|
|
|
if (!minecraft->gameMode->isCutScene())
|
|
{
|
|
if(bDisplayGui && bTwoPlayerSplitscreen)
|
|
{
|
|
// need to apply scale factors depending on the mode
|
|
glPushMatrix();
|
|
glScalef(fScaleFactorWidth, fScaleFactorHeight, fScaleFactorWidth);
|
|
}
|
|
#if RENDER_HUD
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// Display the quick select background, the quick select selection, and the crosshair
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
glColor4f(1, 1, 1, 1);
|
|
|
|
// 4J - this is where to set the blend factor for gui things
|
|
// use the primary player's settings
|
|
unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity);
|
|
|
|
// If the user has started to navigate their quickselect bar, ignore the alpha setting, and display at default value
|
|
float fVal=fAlphaIncrementPerCent*(float)ucAlpha;
|
|
if(ucAlpha<80)
|
|
{
|
|
// check if we have the timer running for the opacity
|
|
unsigned int uiOpacityTimer=app.GetOpacityTimer(iPad);
|
|
if(uiOpacityTimer!=0)
|
|
{
|
|
if(uiOpacityTimer<10)
|
|
{
|
|
float fStep=(80.0f-(float)ucAlpha)/10.0f;
|
|
fVal=fAlphaIncrementPerCent*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep));
|
|
}
|
|
else
|
|
{
|
|
fVal=fAlphaIncrementPerCent*80.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fVal=fAlphaIncrementPerCent*(float)ucAlpha;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fVal=fAlphaIncrementPerCent*(float)ucAlpha;
|
|
}
|
|
|
|
RenderManager.StateSetBlendFactor(0xffffff |(((unsigned int)fVal)<<24));
|
|
currentGuiBlendFactor = fVal / 255.0f;
|
|
// RenderManager.StateSetBlendFactor(0x40ffffff);
|
|
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
|
|
|
|
blitOffset = -90;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// Display the quick select background, the quick select selection, and the crosshair
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
if(bDisplayGui)
|
|
{
|
|
MemSect(31);
|
|
minecraft->textures->bindTexture(TN_GUI_GUI); // 4J was L"/gui/gui.png"
|
|
MemSect(0);
|
|
|
|
shared_ptr<Inventory> inventory = minecraft->player->inventory;
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
// need to apply scale factors depending on the mode
|
|
|
|
// 4J Stu - Moved this push and scale further up as we still need to do it for the few HUD components not replaced by xui
|
|
//glPushMatrix();
|
|
//glScalef(fScaleFactorWidth, fScaleFactorHeight, fScaleFactorWidth);
|
|
|
|
// 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);
|
|
}
|
|
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);
|
|
}
|
|
|
|
|
|
MemSect(31);
|
|
minecraft->textures->bindTexture(TN_GUI_ICONS);//L"/gui/icons.png"));
|
|
MemSect(0);
|
|
glEnable(GL_BLEND);
|
|
RenderManager.StateSetBlendFactor(0xffffff |(((unsigned int)fVal)<<24));
|
|
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
|
|
//glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
|
// 4J Stu - We don't want to adjust the cursor by the safezone, we want it centred
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
blit(iWidthOffset + screenWidth / 2 - 7, (iHeightOffset + screenHeight) / 2 - 7, 0, 0, 16, 16);
|
|
}
|
|
else
|
|
{
|
|
blit(screenWidth / 2 - 7, screenHeight / 2 - 7, 0, 0, 16, 16);
|
|
}
|
|
glDisable(GL_BLEND);
|
|
|
|
// if(bTwoPlayerSplitscreen)
|
|
// {
|
|
// glPopMatrix();
|
|
// }
|
|
|
|
}
|
|
|
|
bool blink = minecraft->player->invulnerableTime / 3 % 2 == 1;
|
|
if (minecraft->player->invulnerableTime < 10) blink = false;
|
|
int iHealth = minecraft->player->getHealth();
|
|
int iLastHealth = minecraft->player->lastHealth;
|
|
random->setSeed(tickCount * 312871);
|
|
|
|
bool foodBlink = false;
|
|
FoodData *foodData = minecraft->player->getFoodData();
|
|
int food = foodData->getFoodLevel();
|
|
int oldFood = foodData->getLastFoodLevel();
|
|
|
|
// if (false) //(true)
|
|
// {
|
|
// renderBossHealth();
|
|
// }
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// Display the experience, food, armour, health and the air bubbles
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
if(bDisplayGui)
|
|
{
|
|
// 4J - added blend for fading gui
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
|
|
|
|
if (minecraft->gameMode->canHurtPlayer())
|
|
{
|
|
int xLeft, xRight;
|
|
// 4J Stu - TODO Work out proper positioning for splitscreen
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
xLeft = iWidthOffset + (screenWidth - quickSelectWidth)/2;
|
|
xRight = iWidthOffset + (screenWidth + quickSelectWidth)/2;
|
|
}
|
|
else
|
|
{
|
|
xLeft = (screenWidth - quickSelectWidth)/2;
|
|
xRight = (screenWidth + quickSelectWidth) / 2;
|
|
}
|
|
|
|
// render experience bar
|
|
int xpNeededForNextLevel = minecraft->player->getXpNeededForNextLevel();
|
|
if (xpNeededForNextLevel > 0)
|
|
{
|
|
int w = 182;
|
|
|
|
int progress = (int) (minecraft->player->experienceProgress * (float) (w + 1));
|
|
|
|
int yo = screenHeight - iSafezoneYHalf - iTooltipsYOffset - 8;
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
yo+=iHeightOffset;
|
|
}
|
|
blit(xLeft, yo, 0, 64, w, 5);
|
|
if (progress > 0)
|
|
{
|
|
blit(xLeft, yo, 0, 69, progress, 5);
|
|
}
|
|
}
|
|
|
|
int yLine1, yLine2;
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
//yo = iHeightOffset + screenHeight - 10 - iSafezoneYHalf - iTooltipsYOffset;
|
|
yLine1 = iHeightOffset + screenHeight - 18 - iSafezoneYHalf - iTooltipsYOffset;
|
|
yLine2 = yLine1 - 10;
|
|
}
|
|
else
|
|
{
|
|
//yo = screenHeight - 10 - iSafezoneYHalf - iTooltipsYOffset;
|
|
yLine1 = screenHeight - 18 - iSafezoneYHalf - iTooltipsYOffset;
|
|
yLine2 = yLine1 - 10;
|
|
}
|
|
|
|
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);
|
|
int healthRowHeight = Math.max(10 - (numHealthRows - 2), 3);
|
|
int yLine2 = yLine1 - (numHealthRows - 1) * healthRowHeight - 10;
|
|
absorption = totalAbsorption;
|
|
|
|
int armor = minecraft->player->getArmorValue();
|
|
int heartOffsetIndex = -1;
|
|
if (minecraft->player->hasEffect(MobEffect::regeneration))
|
|
{
|
|
heartOffsetIndex = tickCount % (int) ceil(maxHealth + 5);
|
|
}
|
|
|
|
// render health and armor
|
|
//minecraft.profiler.push("armor");
|
|
for (int i = 0; i < Player::MAX_HEALTH / 2; i++)
|
|
{
|
|
if (armor > 0)
|
|
{
|
|
int xo = xLeft + i * 8;
|
|
if (i * 2 + 1 < armor) blit(xo, yLine2, 16 + 2 * 9, 9, 9, 9);
|
|
if (i * 2 + 1 == armor) blit(xo, yLine2, 16 + 1 * 9, 9, 9, 9);
|
|
if (i * 2 + 1 > armor) blit(xo, yLine2, 16 + 0 * 9, 9, 9, 9);
|
|
}
|
|
}
|
|
|
|
//minecraft.profiler.popPush("health");
|
|
for (int i = Mth.ceil((maxHealth + totalAbsorption) / 2) - 1; i >= 0; i--)
|
|
{
|
|
int healthTexBaseX = 16;
|
|
if (minecraft.player.hasEffect(MobEffect.poison))
|
|
{
|
|
healthTexBaseX += 4 * 9;
|
|
}
|
|
else if (minecraft.player.hasEffect(MobEffect.wither))
|
|
{
|
|
healthTexBaseX += 8 * 9;
|
|
}
|
|
|
|
int bg = 0;
|
|
if (blink) bg = 1;
|
|
int rowIndex = Mth.ceil((i + 1) / (float) NUM_HEARTS_PER_ROW) - 1;
|
|
int xo = xLeft + (i % NUM_HEARTS_PER_ROW) * 8;
|
|
int yo = yLine1 - rowIndex * healthRowHeight;
|
|
if (currentHealth <= 4)
|
|
{
|
|
yo += random.nextInt(2);
|
|
}
|
|
|
|
if (i == heartOffsetIndex)
|
|
{
|
|
yo -= 2;
|
|
}
|
|
|
|
int y0 = 0;
|
|
|
|
// No hardcore on console
|
|
/*if (minecraft->level.getLevelData().isHardcore())
|
|
{
|
|
y0 = 5;
|
|
}*/
|
|
|
|
blit(xo, yo, 16 + bg * 9, 9 * y0, 9, 9);
|
|
if (blink)
|
|
{
|
|
if (i * 2 + 1 < oldHealth) blit(xo, yo, healthTexBaseX + 6 * 9, 9 * y0, 9, 9);
|
|
if (i * 2 + 1 == oldHealth) blit(xo, yo, healthTexBaseX + 7 * 9, 9 * y0, 9, 9);
|
|
}
|
|
|
|
if (absorption > 0)
|
|
{
|
|
if (absorption == totalAbsorption && totalAbsorption % 2 == 1)
|
|
{
|
|
blit(xo, yo, healthTexBaseX + 17 * 9, 9 * y0, 9, 9);
|
|
}
|
|
else
|
|
{
|
|
blit(xo, yo, healthTexBaseX + 16 * 9, 9 * y0, 9, 9);
|
|
}
|
|
absorption -= 2;
|
|
}
|
|
else
|
|
{
|
|
if (i * 2 + 1 < currentHealth) blit(xo, yo, healthTexBaseX + 4 * 9, 9 * y0, 9, 9);
|
|
if (i * 2 + 1 == currentHealth) blit(xo, yo, healthTexBaseX + 5 * 9, 9 * y0, 9, 9);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<Entity> riding = minecraft->localplayers[iPad].get()->riding;
|
|
std::shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(riding);
|
|
if (riding == NULL)
|
|
{
|
|
// render food
|
|
for (int i = 0; i < FoodConstants::MAX_FOOD / 2; i++)
|
|
{
|
|
int yo = yLine1;
|
|
|
|
|
|
int texBaseX = 16;
|
|
int bg = 0;
|
|
if (minecraft->player->hasEffect(MobEffect::hunger))
|
|
{
|
|
texBaseX += 4 * 9;
|
|
bg = 13;
|
|
}
|
|
|
|
if (minecraft->player->getFoodData()->getSaturationLevel() <= 0)
|
|
{
|
|
if ((tickCount % (food * 3 + 1)) == 0)
|
|
{
|
|
yo += random->nextInt(3) - 1;
|
|
}
|
|
}
|
|
|
|
if (foodBlink) bg = 1;
|
|
int xo = xRight - i * 8 - 9;
|
|
blit(xo, yo, 16 + bg * 9, 9 * 3, 9, 9);
|
|
if (foodBlink)
|
|
{
|
|
if (i * 2 + 1 < oldFood) blit(xo, yo, texBaseX + 6 * 9, 9 * 3, 9, 9);
|
|
if (i * 2 + 1 == oldFood) blit(xo, yo, texBaseX + 7 * 9, 9 * 3, 9, 9);
|
|
}
|
|
if (i * 2 + 1 < food) blit(xo, yo, texBaseX + 4 * 9, 9 * 3, 9, 9);
|
|
if (i * 2 + 1 == food) blit(xo, yo, texBaseX + 5 * 9, 9 * 3, 9, 9);
|
|
}
|
|
}
|
|
else if (living != nullptr)
|
|
{
|
|
// Render mount health
|
|
|
|
int riderCurrentHealth = (int) ceil(living.get()->GetHealth());
|
|
float maxRiderHealth = living->GetMaxHealth();
|
|
int hearts = (int) (maxRiderHealth + .5f) / 2;
|
|
if (hearts > 30)
|
|
{
|
|
hearts = 30;
|
|
}
|
|
|
|
int yo = yLine1;
|
|
int baseHealth = 0;
|
|
|
|
while (hearts > 0)
|
|
{
|
|
int rowHearts = min(hearts, 10);
|
|
hearts -= rowHearts;
|
|
|
|
for (int i = 0; i < rowHearts; i++)
|
|
{
|
|
int texBaseX = 52;
|
|
int bg = 0;
|
|
|
|
if (foodBlink) bg = 1;
|
|
int xo = xRight - i * 8 - 9;
|
|
blit(xo, yo, texBaseX + bg * 9, 9 * 1, 9, 9);
|
|
if (i * 2 + 1 + baseHealth < riderCurrentHealth) blit(xo, yo, texBaseX + 4 * 9, 9 * 1, 9, 9);
|
|
if (i * 2 + 1 + baseHealth == riderCurrentHealth) blit(xo, yo, texBaseX + 5 * 9, 9 * 1, 9, 9);
|
|
}
|
|
yo -= 10;
|
|
baseHealth += 20;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
for (int i = 0; i < count + extra; i++)
|
|
{
|
|
// Air bubbles
|
|
if (i < count) blit(xRight - i * 8 - 9, yLine2, 16, 9 * 2, 9, 9);
|
|
else blit(xRight - i * 8 - 9, yLine2, 16 + 9, 9 * 2, 9, 9);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// 4J-PB - turn off the slot display if a xui menu is up
|
|
|
|
////////////////////////////
|
|
// render the slot contents
|
|
////////////////////////////
|
|
if(bDisplayGui)
|
|
{
|
|
// glDisable(GL_BLEND); 4J - removed - we want to be able to fade our gui
|
|
|
|
glEnable(GL_RESCALE_NORMAL);
|
|
|
|
Lighting::turnOnGui();
|
|
|
|
|
|
int x,y;
|
|
|
|
for (int i = 0; i < 9; i++)
|
|
{
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
x = iWidthOffset + screenWidth / 2 - 9 * 10 + i * 20 + 2;
|
|
y = iHeightOffset + screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22;
|
|
}
|
|
else
|
|
{
|
|
x = screenWidth / 2 - 9 * 10 + i * 20 + 2;
|
|
y = screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22;
|
|
}
|
|
this->renderSlot(i, x, y, a);
|
|
}
|
|
Lighting::turnOff();
|
|
glDisable(GL_RESCALE_NORMAL);
|
|
}
|
|
#endif // RENDER_HUD
|
|
|
|
// 4J - do render of crouched player. This code is largely taken from the inventory render of the player, with some special hard-coded positions
|
|
// worked out by hand from the xui implementation of the crouch icon
|
|
|
|
if(app.GetGameSettings(iPad,eGameSetting_AnimatedCharacter))
|
|
{
|
|
//int playerIdx = minecraft->player->GetXboxPad();
|
|
|
|
static int characterDisplayTimer[4] = {0};
|
|
if( !bDisplayGui )
|
|
{
|
|
characterDisplayTimer[iPad] = 0;
|
|
}
|
|
else if( minecraft->player->isSneaking() )
|
|
{
|
|
characterDisplayTimer[iPad] = 30;
|
|
}
|
|
else if( minecraft->player->isSprinting() )
|
|
{
|
|
characterDisplayTimer[iPad] = 30;
|
|
}
|
|
else if( minecraft->player->abilities.flying)
|
|
{
|
|
characterDisplayTimer[iPad] = 5; // quickly get rid of the player display if they stop flying
|
|
}
|
|
else if( characterDisplayTimer[iPad] > 0 )
|
|
{
|
|
--characterDisplayTimer[iPad];
|
|
}
|
|
bool displayCrouch = minecraft->player->isSneaking() || ( characterDisplayTimer[iPad] > 0 );
|
|
bool displaySprint = minecraft->player->isSprinting() || ( characterDisplayTimer[iPad] > 0 );
|
|
bool displayFlying = minecraft->player->abilities.flying || ( characterDisplayTimer[iPad] > 0 );
|
|
|
|
if( bDisplayGui && (displayCrouch || displaySprint || displayFlying) )
|
|
{
|
|
EntityRenderDispatcher::instance->prepare(minecraft->level, minecraft->textures, minecraft->font, minecraft->cameraTargetPlayer, minecraft->crosshairPickMob, minecraft->options, a);
|
|
glEnable(GL_RESCALE_NORMAL);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
// 4J - TomK now using safe zone values directly instead of the magic number calculation that lived here before (which only worked for medium scale, the other two were off!)
|
|
int xo = iSafezoneXHalf + 10;
|
|
int yo = iSafezoneTopYHalf + 10;
|
|
|
|
#ifdef __PSVITA__
|
|
// align directly with corners, there are no safe zones on vita
|
|
xo = 10;
|
|
yo = 10;
|
|
#endif
|
|
|
|
glPushMatrix();
|
|
glTranslatef(static_cast<float>(xo), static_cast<float>(yo), 50);
|
|
float ss = 12;
|
|
glScalef(-ss, ss, ss);
|
|
glRotatef(180, 0, 0, 1);
|
|
|
|
float oyr = minecraft->player->yRot;
|
|
float oyrO = minecraft->player->yRotO;
|
|
float oxr = minecraft->player->xRot;
|
|
int ofire = minecraft->player->onFire;
|
|
bool ofireflag = minecraft->player->getSharedFlag(Entity::FLAG_ONFIRE);
|
|
|
|
float xd = -40;
|
|
float yd = 10;
|
|
|
|
// 4J Stu - This is all based on the inventory player renderer, with changes to ensure that capes render correctly
|
|
// by minimising the changes to member variables of the player which are all related
|
|
|
|
glRotatef(45 + 90, 0, 1, 0);
|
|
Lighting::turnOn();
|
|
glRotatef(-45 - 90, 0, 1, 0);
|
|
|
|
glRotatef(-(float) atan(yd / 40.0f ) * 20, 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
|
|
// and (180 - bodyRot) is the angle of rotation that is performed within the mob renderer
|
|
glRotatef( bodyRot - ( (float) atan(xd / 40.0f) * 20), 0, 1, 0);
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
// 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->onFire = 0;
|
|
minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE, false);
|
|
|
|
// 4J - TomK don't offset the player. it's easier to align it with the safe zones that way!
|
|
//glTranslatef(0, minecraft->player->heightOffset, 0);
|
|
glTranslatef(0, 0, 0);
|
|
EntityRenderDispatcher::instance->playerRotY = 180;
|
|
EntityRenderDispatcher::instance->isGuiRender = true;
|
|
EntityRenderDispatcher::instance->render(minecraft->player, 0, 0, 0, 0, 1);
|
|
EntityRenderDispatcher::instance->isGuiRender = false;
|
|
|
|
minecraft->player->yRot = oyr;
|
|
minecraft->player->yRotO = oyrO;
|
|
minecraft->player->xRot = oxr;
|
|
minecraft->player->onFire = ofire;
|
|
minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE,ofireflag);
|
|
glPopMatrix();
|
|
Lighting::turnOff();
|
|
glDisable(GL_RESCALE_NORMAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if RENDER_HUD
|
|
// Moved so the opacity blend is applied to it
|
|
if (bDisplayGui && minecraft->gameMode->hasExperience() && minecraft->player->experienceLevel > 0)
|
|
{
|
|
if (true)
|
|
{
|
|
bool blink = false;
|
|
int col = blink ? 0xffffff : 0x80ff20;
|
|
wchar_t formatted[10];
|
|
swprintf(formatted, 10, L"%d",minecraft->player->experienceLevel);
|
|
|
|
wstring str = formatted;
|
|
int x = iWidthOffset + (screenWidth - font->width(str)) / 2;
|
|
int y = screenHeight - iSafezoneYHalf - iTooltipsYOffset;
|
|
// If we're in creative mode, we don't need to offset the XP display so much
|
|
if (minecraft->gameMode->canHurtPlayer())
|
|
{
|
|
y-=18;
|
|
}
|
|
else
|
|
{
|
|
y-=13;
|
|
}
|
|
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
y+=iHeightOffset;
|
|
}
|
|
//int y = screenHeight - 31 - 4;
|
|
font->draw(str, x + 1, y, 0x000000);
|
|
font->draw(str, x - 1, y, 0x000000);
|
|
font->draw(str, x, y + 1, 0x000000);
|
|
font->draw(str, x, y - 1, 0x000000);
|
|
// font->draw(str, x + 1, y + 1, 0x000000);
|
|
// font->draw(str, x - 1, y + 1, 0x000000);
|
|
// font->draw(str, x + 1, y - 1, 0x000000);
|
|
// font->draw(str, x - 1, y - 1, 0x000000);
|
|
font->draw(str, x, y, col);
|
|
}
|
|
}
|
|
#endif // RENDER_HUD
|
|
|
|
// 4J - added to disable blends, which we have enabled previously to allow gui fading
|
|
glDisable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
// if the player is falling asleep we render a dark overlay
|
|
if (minecraft->player->getSleepTimer() > 0)
|
|
{
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
int timer = minecraft->player->getSleepTimer();
|
|
float amount = static_cast<float>(timer) / static_cast<float>(Player::SLEEP_DURATION);
|
|
if (amount > 1)
|
|
{
|
|
// waking up
|
|
amount = 1.0f - (static_cast<float>(timer - Player::SLEEP_DURATION) / static_cast<float>(Player::WAKE_UP_DURATION));
|
|
}
|
|
|
|
int color = static_cast<int>(220.0f * amount) << 24 | (0x101020);
|
|
fill(0, 0, screenWidth/fScaleFactorWidth, screenHeight/fScaleFactorHeight, color);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
// 4J-PB - Request from Mojang to have a red death screen
|
|
if (!minecraft->player->isAlive())
|
|
{
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
int timer = minecraft->player->getDeathFadeTimer();
|
|
float amount = static_cast<float>(timer) / static_cast<float>(Player::DEATHFADE_DURATION);
|
|
|
|
int color = static_cast<int>(220.0f * amount) << 24 | (0x200000);
|
|
fill(0, 0, screenWidth/fScaleFactorWidth, screenHeight/fScaleFactorHeight, color);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
|
// {
|
|
// String str = "" + minecraft.player.getFoodData().getExhaustionLevel() + ", " + minecraft.player.getFoodData().getSaturationLevel();
|
|
// int x = (screenWidth - font.width(str)) / 2;
|
|
// int y = screenHeight - 64;
|
|
// 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<float>(screenWidth - debugLeft - 8) / maxContentWidth;
|
|
float scaleV = static_cast<float>(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<float>(debugLeft), static_cast<float>(debugTop), 0.f);
|
|
glScalef(scale, scale, 1.f);
|
|
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
|
|
|
|
vector<wstring> lines;
|
|
|
|
// Only add version/branch lines if the watermark toggle is enabled
|
|
if (ClientConstants::SHOW_VERSION_WATERMARK) {
|
|
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<int>(xBlockPos)) + L" " + std::to_wstring(static_cast<int>(yBlockPos)) + L" " + std::to_wstring(static_cast<int>(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<float>(screenWidth - debugLeft - 8) / scale;
|
|
float maxWForContent = maxW - static_cast<float>(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<int>(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
|
|
// Jukebox CD message
|
|
if (overlayMessageTime > 0)
|
|
{
|
|
float t = overlayMessageTime - a;
|
|
int alpha = (int) (t * 256 / 20);
|
|
if (alpha > 255) alpha = 255;
|
|
if (alpha > 0)
|
|
{
|
|
glPushMatrix();
|
|
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
glTranslatef((float)((screenWidth / 2)+iWidthOffset), ((float)(screenHeight+iHeightOffset)) - iTooltipsYOffset -12 -iSafezoneYHalf, 0);
|
|
}
|
|
else
|
|
{
|
|
glTranslatef(((float)screenWidth) / 2, ((float)screenHeight) - iTooltipsYOffset - 12 -iSafezoneYHalf, 0);
|
|
}
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
int col = 0xffffff;
|
|
if (animateOverlayMessageColor)
|
|
{
|
|
col = Color::HSBtoRGB(t / 50.0f, 0.7f, 0.6f) & 0xffffff;
|
|
}
|
|
// 4J-PB - this is the string displayed when cds are placed in a jukebox
|
|
font->draw(overlayMessageString,-font->width(overlayMessageString) / 2, -20, col + (alpha << 24));
|
|
glDisable(GL_BLEND);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
unsigned int max = 10;
|
|
bool isChatting = false;
|
|
if (dynamic_cast<ChatScreen *>(minecraft->screen) != NULL)
|
|
{
|
|
max = 20;
|
|
isChatting = true;
|
|
}
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
#if 0 // defined(_WINDOWS64) // Temporarily disable this chat in favor of iggy chat until we have better visual parity
|
|
glPushMatrix();
|
|
glTranslatef(0.0f, static_cast<float>(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
|
|
|
|
if(bDisplayGui)
|
|
{
|
|
int iPad=minecraft->player->GetXboxPad();
|
|
for (unsigned int i = 0; i < guiMessages[iPad].size() && i < max; i++)
|
|
{
|
|
if (guiMessages[iPad][i].ticks < 20 * 10 || isChatting)
|
|
{
|
|
double t = guiMessages[iPad][i].ticks / (20 * 10.0);
|
|
t = 1 - t;
|
|
t = t * 10;
|
|
if (t < 0) t = 0;
|
|
if (t > 1) t = 1;
|
|
t = t * t;
|
|
int alpha = static_cast<int>(255 * t);
|
|
if (isChatting) alpha = 255;
|
|
|
|
if (alpha > 0)
|
|
{
|
|
int x = iSafezoneXHalf+2;
|
|
int y = -(static_cast<int>(i)) * 9;
|
|
if(bTwoPlayerSplitscreen)
|
|
{
|
|
y+= iHeightOffset;
|
|
}
|
|
|
|
wstring msg = guiMessages[iPad][i].string;
|
|
this->fill(0, y - 1, screenWidth/fScaleFactorWidth, y + 8, (alpha / 2) << 24);
|
|
glEnable(GL_BLEND);
|
|
font->drawShadow(msg, iSafezoneXHalf+4, y, 0xffffff + (alpha << 24));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
glPopMatrix();
|
|
#endif
|
|
|
|
// 4J Stu - Copied over but not used
|
|
#if 0
|
|
if (minecraft.player instanceof MultiplayerLocalPlayer && minecraft.options.keyPlayerList.isDown)
|
|
{
|
|
ClientConnection connection = ((MultiplayerLocalPlayer) minecraft.player).connection;
|
|
List<PlayerInfo> playerInfos = connection.playerInfos;
|
|
int slots = connection.maxPlayers;
|
|
|
|
int rows = slots;
|
|
int cols = 1;
|
|
while (rows > 20) {
|
|
cols++;
|
|
rows = (slots + cols - 1) / cols;
|
|
}
|
|
|
|
/*
|
|
* int fakeCount = 39; while (playerInfos.size() > fakeCount)
|
|
* playerInfos.remove(playerInfos.size() - 1); while (playerInfos.size() <
|
|
* fakeCount) playerInfos.add(new PlayerInfo("fiddle"));
|
|
*/
|
|
|
|
int slotWidth = 300 / cols;
|
|
if (slotWidth > 150) slotWidth = 150;
|
|
|
|
int xxo = (screenWidth - cols * slotWidth) / 2;
|
|
int yyo = 10;
|
|
fill(xxo - 1, yyo - 1, xxo + slotWidth * cols, yyo + 9 * rows, 0x80000000);
|
|
for (int i = 0; i < slots; i++) {
|
|
int xo = xxo + i % cols * slotWidth;
|
|
int yo = yyo + i / cols * 9;
|
|
|
|
fill(xo, yo, xo + slotWidth - 1, yo + 8, 0x20ffffff);
|
|
glColor4f(1, 1, 1, 1);
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
if (i < playerInfos.size()) {
|
|
PlayerInfo pl = playerInfos.get(i);
|
|
font.drawShadow(pl.name, xo, yo, 0xffffff);
|
|
minecraft.textures.bind(minecraft.textures.loadTexture("/gui/icons.png"));
|
|
int xt = 0;
|
|
int yt = 0;
|
|
xt = 0;
|
|
yt = 0;
|
|
if (pl.latency < 0) yt = 5;
|
|
else if (pl.latency < 150) yt = 0;
|
|
else if (pl.latency < 300) yt = 1;
|
|
else if (pl.latency < 600) yt = 2;
|
|
else if (pl.latency < 1000) yt = 3;
|
|
else yt = 4;
|
|
|
|
blitOffset += 100;
|
|
blit(xo + slotWidth - 12, yo, 0 + xt * 10, 176 + yt * 8, 10, 8);
|
|
blitOffset -= 100;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(bDisplayGui && bTwoPlayerSplitscreen)
|
|
{
|
|
// pop the scaled matrix
|
|
glPopMatrix();
|
|
}
|
|
|
|
glColor4f(1, 1, 1, 1);
|
|
glDisable(GL_BLEND);
|
|
glEnable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
// Moved to the xui base scene
|
|
// void Gui::renderBossHealth(void)
|
|
// {
|
|
// if (EnderDragonRenderer::bossInstance == NULL) return;
|
|
//
|
|
// shared_ptr<EnderDragon> 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);
|
|
// }
|
|
//
|
|
// 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::renderPumpkin(int w, int h)
|
|
{
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDepthMask(false);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(1, 1, 1, 1);
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
MemSect(31);
|
|
minecraft->textures->bindTexture(&PUMPKIN_BLUR_LOCATION);
|
|
MemSect(0);
|
|
Tesselator *t = Tesselator::getInstance();
|
|
t->begin();
|
|
t->vertexUV(static_cast<float>(0), static_cast<float>(h), static_cast<float>(-90), static_cast<float>(0), static_cast<float>(1));
|
|
t->vertexUV(static_cast<float>(w), static_cast<float>(h), static_cast<float>(-90), static_cast<float>(1), static_cast<float>(1));
|
|
t->vertexUV(static_cast<float>(w), static_cast<float>(0), static_cast<float>(-90), static_cast<float>(1), static_cast<float>(0));
|
|
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(-90), static_cast<float>(0), static_cast<float>(0));
|
|
t->end();
|
|
glDepthMask(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glColor4f(1, 1, 1, 1);
|
|
|
|
}
|
|
|
|
void Gui::renderVignette(float br, int w, int h)
|
|
{
|
|
br = 1 - br;
|
|
if (br < 0) br = 0;
|
|
if (br > 1) br = 1;
|
|
tbr += (br - tbr) * 0.01f;
|
|
|
|
#if 0 // 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);
|
|
glColor4f(tbr, tbr, tbr, 1);
|
|
glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN__BLUR__MISC_VIGNETTE));//L"%blur%/misc/vignette.png"));
|
|
Tesselator *t = Tesselator::getInstance();
|
|
t->begin();
|
|
t->vertexUV((float)(0), (float)( h), (float)( -90), (float)( 0), (float)( 1));
|
|
t->vertexUV((float)(w), (float)( h), (float)( -90), (float)( 1), (float)( 1));
|
|
t->vertexUV((float)(w), (float)( 0), (float)( -90), (float)( 1), (float)( 0));
|
|
t->vertexUV((float)(0), (float)( 0), (float)( -90), (float)( 0), (float)( 0));
|
|
t->end();
|
|
glDepthMask(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glColor4f(1, 1, 1, 1);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
#endif
|
|
}
|
|
|
|
void Gui::renderTp(float br, int w, int h)
|
|
{
|
|
if (br < 1)
|
|
{
|
|
br = br * br;
|
|
br = br * br;
|
|
br = br * 0.8f + 0.2f;
|
|
}
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDepthMask(false);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(1, 1, 1, br);
|
|
MemSect(31);
|
|
minecraft->textures->bindTexture(&TextureAtlas::LOCATION_BLOCKS);
|
|
MemSect(0);
|
|
|
|
Icon *slot = Tile::portalTile->getTexture(Facing::UP);
|
|
float u0 = slot->getU0();
|
|
float v0 = slot->getV0();
|
|
float u1 = slot->getU1();
|
|
float v1 = slot->getV1();
|
|
Tesselator *t = Tesselator::getInstance();
|
|
t->begin();
|
|
t->vertexUV(static_cast<float>(0), static_cast<float>(h), static_cast<float>(-90), (float)( u0), (float)( v1));
|
|
t->vertexUV(static_cast<float>(w), static_cast<float>(h), static_cast<float>(-90), (float)( u1), (float)( v1));
|
|
t->vertexUV(static_cast<float>(w), static_cast<float>(0), static_cast<float>(-90), (float)( u1), (float)( v0));
|
|
t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(-90), (float)( u0), (float)( v0));
|
|
t->end();
|
|
glDepthMask(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glColor4f(1, 1, 1, 1);
|
|
|
|
}
|
|
|
|
void Gui::renderSlot(int slot, int x, int y, float a)
|
|
{
|
|
shared_ptr<ItemInstance> item = minecraft->player->inventory->items[slot];
|
|
if (item == NULL) return;
|
|
|
|
float pop = item->popTime - a;
|
|
if (pop > 0)
|
|
{
|
|
glPushMatrix();
|
|
float squeeze = 1 + pop / static_cast<float>(Inventory::POP_TIME_DURATION);
|
|
glTranslatef(static_cast<float>(x + 8), static_cast<float>(y + 12), 0);
|
|
glScalef(1 / squeeze, (squeeze + 1) / 2, 1);
|
|
glTranslatef(static_cast<float>(-(x + 8)), static_cast<float>(-(y + 12)), 0);
|
|
}
|
|
|
|
itemRenderer->renderAndDecorateItem(minecraft->font, minecraft->textures, item, x, y);
|
|
|
|
if (pop > 0)
|
|
{
|
|
glPopMatrix();
|
|
}
|
|
|
|
itemRenderer->renderGuiItemDecorations(minecraft->font, minecraft->textures, item, x, y);
|
|
|
|
}
|
|
|
|
void Gui::tick()
|
|
{
|
|
if (overlayMessageTime > 0) overlayMessageTime--;
|
|
tickCount++;
|
|
|
|
for(int iPad=0;iPad<XUSER_MAX_COUNT;iPad++)
|
|
{
|
|
// 4J Stu - Fix for #10929 - MP LAB: Network Disconnects: Host does not receive an error message stating the client left the game when viewing the Pause Menu.
|
|
// We don't show the guiMessages when a menu is up, so don't fade them out
|
|
if(!ui.GetMenuDisplayed(iPad))
|
|
{
|
|
for (auto& it : guiMessages[iPad])
|
|
{
|
|
it.ticks++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Gui::clearMessages(int iPad)
|
|
{
|
|
if(iPad==-1)
|
|
{
|
|
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
|
{
|
|
if(minecraft->localplayers[i])
|
|
{
|
|
guiMessages[i].clear();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
guiMessages[iPad].clear();
|
|
}
|
|
}
|
|
|
|
|
|
void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
|
|
{
|
|
wstring string = _string; // 4J - Take copy of input as it is const
|
|
//int iScale=1;
|
|
|
|
//if((minecraft->player->m_iScreenSection==C4JRender::VIEWPORT_TYPE_SPLIT_TOP) ||
|
|
// (minecraft->player->m_iScreenSection==C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM))
|
|
//{
|
|
// iScale=2;
|
|
//}
|
|
|
|
// while (minecraft->font->width(string) > (m_iMaxMessageWidth*iScale))
|
|
//{
|
|
// unsigned int i = 1;
|
|
// while (i < string.length() && minecraft->font->width(string.substr(0, i + 1)) <= (m_iMaxMessageWidth*iScale))
|
|
// {
|
|
// i++;
|
|
// }
|
|
// int iLast=string.find_last_of(L" ",i);
|
|
|
|
// // if a space was found, include the space on this line
|
|
// if(iLast!=i)
|
|
// {
|
|
// iLast++;
|
|
// }
|
|
// addMessage(string.substr(0, iLast), iPad);
|
|
// string = string.substr(iLast);
|
|
// }
|
|
|
|
int maximumChars;
|
|
|
|
switch(minecraft->player->m_iScreenSection)
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
|
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
|
|
if(RenderManager.IsHiDef())
|
|
{
|
|
maximumChars = 105;
|
|
}
|
|
else
|
|
{
|
|
maximumChars = 55;
|
|
}
|
|
#ifdef __PSVITA__
|
|
maximumChars = 90;
|
|
#endif
|
|
switch(XGetLanguage())
|
|
{
|
|
case XC_LANGUAGE_JAPANESE:
|
|
case XC_LANGUAGE_TCHINESE:
|
|
case XC_LANGUAGE_KOREAN:
|
|
if(RenderManager.IsHiDef())
|
|
{
|
|
maximumChars = 70;
|
|
}
|
|
else
|
|
{
|
|
maximumChars = 35;
|
|
}
|
|
#ifdef __PSVITA__
|
|
maximumChars = 55;
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
maximumChars = 55;
|
|
switch(XGetLanguage())
|
|
{
|
|
case XC_LANGUAGE_JAPANESE:
|
|
case XC_LANGUAGE_TCHINESE:
|
|
case XC_LANGUAGE_KOREAN:
|
|
maximumChars = 35;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
while (string.length() > maximumChars)
|
|
{
|
|
unsigned int i = 1;
|
|
while (i < string.length() && (i + 1) <= maximumChars)
|
|
{
|
|
i++;
|
|
}
|
|
size_t iLast=string.find_last_of(L" ",i);
|
|
switch(XGetLanguage())
|
|
{
|
|
case XC_LANGUAGE_JAPANESE:
|
|
case XC_LANGUAGE_TCHINESE:
|
|
case XC_LANGUAGE_KOREAN:
|
|
iLast = maximumChars;
|
|
break;
|
|
default:
|
|
iLast=string.find_last_of(L" ",i);
|
|
break;
|
|
}
|
|
|
|
// if a space was found, include the space on this line
|
|
if(iLast!=i)
|
|
{
|
|
iLast++;
|
|
}
|
|
addMessage(string.substr(0, iLast), iPad, bIsDeathMessage);
|
|
string = string.substr(iLast);
|
|
}
|
|
|
|
if(iPad==-1)
|
|
{
|
|
// add to all
|
|
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
|
{
|
|
if(minecraft->localplayers[i] && !(bIsDeathMessage && app.GetGameSettings(i,eGameSetting_DeathMessages)==0))
|
|
{
|
|
guiMessages[i].insert(guiMessages[i].begin(), GuiMessage(string));
|
|
while (guiMessages[i].size() > 50)
|
|
{
|
|
guiMessages[i].pop_back();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(!(bIsDeathMessage && app.GetGameSettings(iPad,eGameSetting_DeathMessages)==0))
|
|
{
|
|
guiMessages[iPad].insert(guiMessages[iPad].begin(), GuiMessage(string));
|
|
while (guiMessages[iPad].size() > 50)
|
|
{
|
|
guiMessages[iPad].pop_back();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// 4J Added
|
|
float Gui::getOpacity(int iPad, DWORD index)
|
|
{
|
|
float opacityPercentage = 0;
|
|
if (guiMessages[iPad].size() > index && guiMessages[iPad][index].ticks < 20 * 10)
|
|
{
|
|
double t = guiMessages[iPad][index].ticks / (20 * 10.0);
|
|
t = 1 - t;
|
|
t = t * 10;
|
|
if (t < 0) t = 0;
|
|
if (t > 1) t = 1;
|
|
t = t * t;
|
|
opacityPercentage = t;
|
|
}
|
|
return opacityPercentage;
|
|
}
|
|
|
|
float Gui::getJukeboxOpacity(int iPad)
|
|
{
|
|
float t = overlayMessageTime - lastTickA;
|
|
int alpha = static_cast<int>(t * 256 / 20);
|
|
if (alpha > 255) alpha = 255;
|
|
alpha /= 255;
|
|
|
|
return alpha;
|
|
}
|
|
|
|
void Gui::setNowPlaying(const wstring& string)
|
|
{
|
|
// overlayMessageString = L"Now playing: " + string;
|
|
overlayMessageString = app.GetString(IDS_NOWPLAYING) + string;
|
|
overlayMessageTime = 20 * 3;
|
|
animateOverlayMessageColor = true;
|
|
}
|
|
|
|
void Gui::displayClientMessage(int messageId, int iPad)
|
|
{
|
|
//Language *language = Language::getInstance();
|
|
wstring languageString = app.GetString(messageId);//language->getElement(messageId);
|
|
|
|
addMessage(languageString, iPad);
|
|
}
|
|
|
|
// 4J Added
|
|
void Gui::renderGraph(int dataLength, int dataPos, int64_t *dataA, float dataAScale, int dataAWarning, int64_t *dataB, float dataBScale, int dataBWarning)
|
|
{
|
|
int height = minecraft->height;
|
|
// This causes us to cover xScale*dataLength pixels in the horizontal
|
|
int xScale = 1;
|
|
if(dataA != NULL && dataB != NULL) xScale = 2;
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, static_cast<float>(minecraft->width), static_cast<float>(height), 0, 1000, 3000);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -2000);
|
|
|
|
glLineWidth(1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
Tesselator *t = Tesselator::getInstance();
|
|
|
|
t->begin(GL_LINES);
|
|
for (int i = 0; i < dataLength; i++)
|
|
{
|
|
int col = ((i - dataPos) & (dataLength - 1)) * 255 / dataLength;
|
|
int cc = col * col / 255;
|
|
cc = cc * cc / 255;
|
|
int cc2 = cc * cc / 255;
|
|
cc2 = cc2 * cc2 / 255;
|
|
|
|
if( dataA != NULL )
|
|
{
|
|
if (dataA[i] > dataAWarning)
|
|
{
|
|
t->color(0xff000000 + cc * 65536);
|
|
}
|
|
else
|
|
{
|
|
t->color(0xff000000 + cc * 256);
|
|
}
|
|
|
|
int64_t aVal = dataA[i] / dataAScale;
|
|
|
|
t->vertex((float)(xScale*i + 0.5f), (float)( height - aVal + 0.5f), static_cast<float>(0));
|
|
t->vertex((float)(xScale*i + 0.5f), (float)( height + 0.5f), static_cast<float>(0));
|
|
}
|
|
|
|
if( dataB != NULL )
|
|
{
|
|
if (dataB[i]>dataBWarning)
|
|
{
|
|
t->color(0xff000000 + cc * 65536 + cc * 256 + cc * 1);
|
|
}
|
|
else
|
|
{
|
|
t->color(0xff808080 + cc/2 * 256);
|
|
}
|
|
|
|
int64_t bVal = dataB[i] / dataBScale;
|
|
|
|
t->vertex((float)(xScale*i + (xScale - 1) + 0.5f), (float)( height - bVal + 0.5f), static_cast<float>(0));
|
|
t->vertex((float)(xScale*i + (xScale - 1) + 0.5f), (float)( height + 0.5f), static_cast<float>(0));
|
|
}
|
|
}
|
|
t->end();
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
void Gui::renderStackedGraph(int dataPos, int dataLength, int dataSources, int64_t (*func)(unsigned int dataPos, unsigned int dataSource) )
|
|
{
|
|
int height = minecraft->height;
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, static_cast<float>(minecraft->width), static_cast<float>(height), 0, 1000, 3000);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -2000);
|
|
|
|
glLineWidth(1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
Tesselator *t = Tesselator::getInstance();
|
|
|
|
t->begin(GL_LINES);
|
|
int64_t thisVal = 0;
|
|
int64_t topVal = 0;
|
|
for (int i = 0; i < dataLength; i++)
|
|
{
|
|
thisVal = 0;
|
|
topVal = 0;
|
|
int col = ((i - dataPos) & (dataLength - 1)) * 255 / dataLength;
|
|
int cc = col * col / 255;
|
|
cc = cc * cc / 255;
|
|
int cc2 = cc * cc / 255;
|
|
cc2 = cc2 * cc2 / 255;
|
|
|
|
|
|
for(unsigned int source = 0; source < dataSources; ++source )
|
|
{
|
|
thisVal = func( i, source );
|
|
|
|
if( thisVal > 0 )
|
|
{
|
|
float vary = static_cast<float>(source)/dataSources;
|
|
int fColour = floor(vary * 0xffffff);
|
|
|
|
int colour = 0xff000000 + fColour;
|
|
//printf("Colour is %x\n", colour);
|
|
t->color(colour);
|
|
|
|
t->vertex((float)(i + 0.5f), (float)( height - topVal - thisVal + 0.5f), static_cast<float>(0));
|
|
t->vertex((float)(i + 0.5f), (float)( height - topVal + 0.5f), static_cast<float>(0));
|
|
|
|
topVal += thisVal;
|
|
}
|
|
}
|
|
|
|
// Draw some horizontals
|
|
for(unsigned int horiz = 1; horiz < 7; ++horiz )
|
|
{
|
|
t->color(0xff000000);
|
|
|
|
t->vertex((float)(0 + 0.5f), (float)( height - (horiz*100) + 0.5f), static_cast<float>(0));
|
|
t->vertex((float)(dataLength + 0.5f), (float)( height - (horiz*100) + 0.5f), static_cast<float>(0));
|
|
}
|
|
}
|
|
t->end();
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
}
|