mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-03-22 07:48:13 +05:00
* Fix split-screen join failing when connecting to a remote host via UI
When a non-host client connected to a remote server through the in-game
UI (as opposed to the -ip/-port command line flags), the global variables
g_Win64MultiplayerIP and g_Win64MultiplayerPort were never updated from
their defaults ("127.0.0.1" and the default port). JoinSplitScreen()
relies on these globals to open a second TCP connection for the local
split-screen pad, so it would always attempt to connect to localhost,
failing immediately on any remote session.
Fix: update g_Win64MultiplayerIP and g_Win64MultiplayerPort inside
JoinGame() once the primary connection is established. This ensures
subsequent JoinSplitScreen() calls always reach the correct host
regardless of how the session was joined.
Additionally, guard PushFreeSmallId() against recycling smallIds in the
range [0, XUSER_MAX_COUNT), which are permanently reserved for the
host's local controller slots. Previously, if a host-side local pad
disconnected its smallId could re-enter the free pool and be handed
to an incoming remote client, causing that client's IQNetPlayer slot
to collide with a local pad slot on the non-host machine.
* Fix tutorial popup positioning in split-screen viewports
Replace the manual switch-case that computed viewport origin with the shared GetViewportRect/Fit16x9 helpers (from UISplitScreenHelpers.h). This ensures the tutorial popup is positioned and scaled consistently with the rest of the split-screen UI, fitting a 16:9 box inside each viewport and applying safezone offsets correctly.
Also adds missing default:break to safezone switch statements to silence compiler warnings.
Made-with: Cursor
* Prevent split-screen join when game window is not focused
Add g_KBMInput.IsWindowFocused() guard to the tryJoin condition so that gamepad input from background windows does not accidentally trigger a split-screen player join. This avoids phantom joins when the user is interacting with another application.
* Open debug overlay in fullscreen UI group during split-screen
Pass eUIGroup_Fullscreen to NavigateToScene when opening the debug overlay, so it spans the entire window instead of being confined to a single split-screen viewport. This makes the debug info readable regardless of the current split-screen layout.
* Fix non-host split-screen connections missing world updates
Previously, secondary (non-host) split-screen connections used isPrimaryConnection()
to gate nearly all world update packets, meaning the second local player would never
receive tile updates, entity movement, sounds, particles, explosions, etc.
The fix introduces per-connection tracking of which entities and chunks each
ClientConnection has loaded, and uses that information to decide whether a secondary
connection needs to process a given packet or if the primary connection already
handled it.
New members in ClientConnection:
- m_trackedEntityIds: set of entity IDs this connection has received AddEntity/AddMob/AddPlayer etc. for
- m_visibleChunks: set of chunk coordinates (packed into int64) this connection has marked visible
- Both sets are cleared on close(), respawn (dimension change), and destructor
New helpers:
- findPrimaryConnection(): walks the MultiPlayerLevel connection list to find the connection on the primary pad
- shouldProcessForEntity(id): secondary connection skips the packet only if the primary is already tracking that entity
- shouldProcessForPosition(x, z): secondary connection skips the packet only if the primary already has that chunk visible
- anyOtherConnectionHasChunk(x, z): used when a chunk becomes invisible to avoid hiding it from the level if another connection still needs it
- isTrackingEntity(id): public accessor used by shouldProcessForEntity on the primary connection
Packet handler changes:
- handleMoveEntity, handleMoveEntitySmall, handleSetEntityMotion, handleTakeItemEntity:
replaced isPrimaryConnection() with shouldProcessForEntity() so secondary
connections still process movement for entities they know about
- handleExplosion, handleLevelEvent:
replaced isPrimaryConnection() with shouldProcessForPosition() so block
destruction and level events fire for the correct connection based on chunks
- handleChunkTilesUpdate, handleBlockRegionUpdate, handleTileUpdate, handleSignUpdate,
handleTileEntityData, handleTileEvent, handleTileDestruction, handleComplexItemData,
handleSoundEvent, handleParticleEvent:
removed the isPrimaryConnection() guard entirely -- these are world-state updates
that all connections must process regardless of which pad is primary
- handleChunkVisibilityArea / handleChunkVisibility:
now populate m_visibleChunks; on visibility=false, setChunkVisible(false) is
only called on the level if no other connection still has that chunk loaded
- handleAddEntity, handleAddExperienceOrb, handleAddPainting, handleAddPlayer,
handleAddMob: now insert into m_trackedEntityIds on arrival
- handleRemoveEntity: now erases from m_trackedEntityIds on removal
- handleLevelEvent: removed a duplicate levelEvent() call that was always firing
regardless of the isPrimaryConnection() check above it (latent bug)
MultiPlayerLevel: added friend class ClientConnection to allow access to the
connections list without exposing it publicly.
* Fix fullscreen progress screen swallowing input before load completes
Two issues in UIScene_FullscreenProgress::handleInput:
1. The touchpad/button press that triggers movie skip or input forwarding
had no guard on m_threadCompleted, so pressing a button during the loading
phase would fire the skip/send logic before the background thread finished.
Added the m_threadCompleted check so that path is only reachable once
the load is actually done.
2. The `handled = true` assignment was missing from that branch, so input
events were not being consumed and could fall through to other handlers.
Added it unconditionally at the end of the block.
* Update player count decrement logic in PlatformNetworkManagerStub
Refactor the condition for decrementing the player count in CPlatformNetworkManagerStub::DoWork. The previous check was replaced with a while loop to ensure that the player count is only decremented when there are more than one player and the last player's custom data value is zero. This change improves the handling of player connections in the network manager.
* 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.
* 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.
1697 lines
54 KiB
C++
1697 lines
54 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();
|
|
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;
|
|
|
|
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 = (int)Mth.ceil(healthHalves) - 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))
|
|
{
|
|
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
|
|
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);
|
|
|
|
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
|
|
// 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 = xRotAngle;
|
|
|
|
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);
|
|
// }
|
|
|
|
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();
|
|
}
|
|
|
|
#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<float>(guiScale) * 1.0f;
|
|
const int debugLeft = 1;
|
|
const int debugTop = 1;
|
|
|
|
glTranslatef(static_cast<float>(debugLeft), static_cast<float>(debugTop), 0.f);
|
|
glScalef(fontScale, fontScale, 1.f);
|
|
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
|
|
|
|
vector<wstring> 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<float>(g_rScreenWidth) - debugLeft - 8) / fontScale;
|
|
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"");
|
|
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(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);
|
|
}
|
|
|
|
// 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);
|
|
}
|