Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a00b9962bb | |||
| 00fef6e9d2 | |||
| a82e0ccf82 |
@@ -342,7 +342,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
|
||||
Level *dimensionLevel = minecraft->getLevel( packet->dimension );
|
||||
if( dimensionLevel == nullptr )
|
||||
{
|
||||
level = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
level = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, packet->m_isHardcore, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
|
||||
// 4J Stu - We want to share the SavedDataStorage between levels
|
||||
int otherDimensionId = packet->dimension == 0 ? -1 : 0;
|
||||
@@ -411,7 +411,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
|
||||
activeLevel = minecraft->getLevel(otherDimensionId);
|
||||
}
|
||||
|
||||
MultiPlayerLevel *dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
MultiPlayerLevel *dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, packet->m_isHardcore, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
|
||||
dimensionLevel->savedDataStorage = activeLevel->savedDataStorage;
|
||||
|
||||
@@ -2870,7 +2870,7 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
|
||||
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->getLevel( packet->dimension );
|
||||
if( dimensionLevel == nullptr )
|
||||
{
|
||||
dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->mapSeed, packet->playerGameType, false, minecraft->level->getLevelData()->isHardcore(), packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->mapSeed, packet->playerGameType, false, packet->m_isHardcore, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty);
|
||||
|
||||
// 4J Stu - We want to shared the savedDataStorage between both levels
|
||||
//if( dimensionLevel->savedDataStorage != nullptr )
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#define GAME_HOST_OPTION_BITMASK_DOTILEDROPS 0x08000000
|
||||
#define GAME_HOST_OPTION_BITMASK_NATURALREGEN 0x10000000
|
||||
#define GAME_HOST_OPTION_BITMASK_DODAYLIGHTCYCLE 0x20000000
|
||||
#define GAME_HOST_OPTION_BITMASK_HARDCORE 0x40000000 // 4J Added - for hardcore mode
|
||||
#define GAME_HOST_OPTION_BITMASK_ALL 0xFFFFFFFF
|
||||
|
||||
#define GAME_HOST_OPTION_BITMASK_WORLDSIZE_BITSHIFT 20
|
||||
|
||||
@@ -648,6 +648,7 @@ enum eGameHostOption
|
||||
eGameHostOption_DoTileDrops,
|
||||
eGameHostOption_NaturalRegeneration,
|
||||
eGameHostOption_DoDaylightCycle,
|
||||
eGameHostOption_Hardcore, // 4J Added - for hardcore mode
|
||||
};
|
||||
|
||||
// 4J-PB - If any new DLC items are added to the TMSFiles, this array needs updated
|
||||
|
||||
@@ -8084,6 +8084,16 @@ void CMinecraftApp::SetGameHostOption(unsigned int &uiHostSettings, eGameHostOpt
|
||||
uiHostSettings&=~GAME_HOST_OPTION_BITMASK_WORLDSIZE;
|
||||
uiHostSettings|=(GAME_HOST_OPTION_BITMASK_WORLDSIZE & (uiVal<<GAME_HOST_OPTION_BITMASK_WORLDSIZE_BITSHIFT));
|
||||
break;
|
||||
case eGameHostOption_Hardcore: // 4J Added - for hardcore mode
|
||||
if(uiVal!=0)
|
||||
{
|
||||
uiHostSettings |= GAME_HOST_OPTION_BITMASK_HARDCORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HARDCORE;
|
||||
}
|
||||
break;
|
||||
case eGameHostOption_All:
|
||||
uiHostSettings=uiVal;
|
||||
break;
|
||||
@@ -8185,6 +8195,9 @@ unsigned int CMinecraftApp::GetGameHostOption(unsigned int uiHostSettings, eGame
|
||||
case eGameHostOption_DoDaylightCycle:
|
||||
return !(uiHostSettings&GAME_HOST_OPTION_BITMASK_DODAYLIGHTCYCLE);
|
||||
break;
|
||||
case eGameHostOption_Hardcore: // 4J Added - for hardcore mode
|
||||
return (uiHostSettings&GAME_HOST_OPTION_BITMASK_HARDCORE) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -805,6 +805,10 @@ public:
|
||||
void SetCorruptSaveDeleted(bool bVal) {m_bCorruptSaveDeleted=bVal;}
|
||||
bool GetCorruptSaveDeleted(void) {return m_bCorruptSaveDeleted;}
|
||||
|
||||
// 4J Added: Store save folder name for hardcore world deletion on Win64
|
||||
void SetCurrentSaveFolderName(const wstring& name) { m_currentSaveFolderName = name; }
|
||||
const wstring& GetCurrentSaveFolderName() const { return m_currentSaveFolderName; }
|
||||
|
||||
void EnterSaveNotificationSection();
|
||||
void LeaveSaveNotificationSection();
|
||||
private:
|
||||
@@ -826,6 +830,7 @@ private:
|
||||
CRITICAL_SECTION csAdditionalSkinBoxes;
|
||||
CRITICAL_SECTION csAnimOverrideBitmask;
|
||||
bool m_bCorruptSaveDeleted;
|
||||
wstring m_currentSaveFolderName; // 4J Added: for hardcore world deletion on Win64
|
||||
|
||||
DWORD m_dwAdditionalModelParts[XUSER_MAX_COUNT];
|
||||
|
||||
|
||||
@@ -410,11 +410,72 @@ int IUIScene_PauseMenu::ExitWorldThreadProc( void* lpParameter )
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
static bool Win64_DeleteSaveDirectory(const wchar_t* wPath)
|
||||
{
|
||||
wchar_t wSearch[MAX_PATH];
|
||||
swprintf_s(wSearch, MAX_PATH, L"%s\\*", wPath);
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = FindFirstFileW(wSearch, &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0) continue;
|
||||
wchar_t wChild[MAX_PATH];
|
||||
swprintf_s(wChild, MAX_PATH, L"%s\\%s", wPath, fd.cFileName);
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
Win64_DeleteSaveDirectory(wChild);
|
||||
else
|
||||
DeleteFileW(wChild);
|
||||
} while (FindNextFileW(hFind, &fd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
return RemoveDirectoryW(wPath) != 0;
|
||||
}
|
||||
#endif // _WINDOWS64
|
||||
|
||||
// This function performs the meat of exiting from a level. It should be called from a thread other than the main thread.
|
||||
void IUIScene_PauseMenu::_ExitWorld(LPVOID lpParameter)
|
||||
{
|
||||
Minecraft *pMinecraft=Minecraft::GetInstance();
|
||||
|
||||
// 4J Added: Capture hardcore delete info before the server is destroyed
|
||||
#ifdef _WINDOWS64
|
||||
bool shouldDeleteHardcoreWorld = false;
|
||||
wstring hardcoreSaveFolderName;
|
||||
if (MinecraftServer::getInstance() != nullptr && MinecraftServer::getInstance()->getDeleteWorldOnExit())
|
||||
{
|
||||
shouldDeleteHardcoreWorld = true;
|
||||
// Try 1: Use the save folder name stored by UIScene_LoadMenu::StartGameFromSave (works for existing saves)
|
||||
hardcoreSaveFolderName = app.GetCurrentSaveFolderName();
|
||||
if (!hardcoreSaveFolderName.empty())
|
||||
{
|
||||
app.DebugPrintf("Hardcore mode: save folder from app = '%ls'\n", hardcoreSaveFolderName.c_str());
|
||||
}
|
||||
// Try 2: StorageManager (may work for new saves after first autosave)
|
||||
if (hardcoreSaveFolderName.empty())
|
||||
{
|
||||
char szSaveFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
StorageManager.GetSaveUniqueFilename(szSaveFolder);
|
||||
if (szSaveFolder[0] != '\0')
|
||||
{
|
||||
wchar_t wSaveFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
mbstowcs(wSaveFolder, szSaveFolder, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
hardcoreSaveFolderName = wSaveFolder;
|
||||
app.DebugPrintf("Hardcore mode: save folder from StorageManager = '%s'\n", szSaveFolder);
|
||||
}
|
||||
}
|
||||
// Try 3: Stored during loadLevel
|
||||
if (hardcoreSaveFolderName.empty())
|
||||
{
|
||||
hardcoreSaveFolderName = MinecraftServer::getInstance()->getSaveFolderName();
|
||||
app.DebugPrintf("Hardcore mode: save folder from server = '%ls'\n", hardcoreSaveFolderName.c_str());
|
||||
}
|
||||
MinecraftServer::getInstance()->setDeleteWorldOnExit(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
int exitReasonStringId = pMinecraft->progressRenderer->getCurrentTitle();
|
||||
int exitReasonTitleId = IDS_CONNECTION_LOST;
|
||||
|
||||
@@ -625,6 +686,17 @@ void IUIScene_PauseMenu::_ExitWorld(LPVOID lpParameter)
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
// 4J Added: Hardcore mode — delete world save data now that the server is fully stopped
|
||||
#ifdef _WINDOWS64
|
||||
if (shouldDeleteHardcoreWorld && !hardcoreSaveFolderName.empty())
|
||||
{
|
||||
wchar_t wFolderPath[MAX_PATH] = {};
|
||||
swprintf_s(wFolderPath, MAX_PATH, L"Windows64\\GameHDD\\%s", hardcoreSaveFolderName.c_str());
|
||||
app.DebugPrintf("Hardcore mode: Deleting world save folder '%ls'\n", wFolderPath);
|
||||
Win64_DeleteSaveDirectory(wFolderPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
pMinecraft->setLevel(nullptr,exitReasonStringId,nullptr,saveStats);
|
||||
|
||||
TelemetryManager->Flush();
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define GAME_CREATE_ONLINE_TIMER_ID 0
|
||||
#define GAME_CREATE_ONLINE_TIMER_TIME 100
|
||||
|
||||
static bool s_bHardcore = false; // 4J Added: tracks when difficulty slider is at Hardcore position (file-scope to avoid header layout changes)
|
||||
|
||||
int UIScene_CreateWorldMenu::m_iDifficultyTitleSettingA[4]=
|
||||
{
|
||||
IDS_DIFFICULTY_TITLE_PEACEFUL,
|
||||
@@ -59,8 +61,9 @@ UIScene_CreateWorldMenu::UIScene_CreateWorldMenu(int iPad, void *initData, UILay
|
||||
|
||||
WCHAR TempString[256];
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[app.GetGameSettings(m_iPad,eGameSetting_Difficulty)]));
|
||||
m_sliderDifficulty.init(TempString,eControl_Difficulty,0,3,app.GetGameSettings(m_iPad,eGameSetting_Difficulty));
|
||||
m_sliderDifficulty.init(TempString,eControl_Difficulty,0,4,app.GetGameSettings(m_iPad,eGameSetting_Difficulty));
|
||||
|
||||
s_bHardcore = false;
|
||||
m_MoreOptionsParams.bGenerateOptions=TRUE;
|
||||
m_MoreOptionsParams.bStructures=TRUE;
|
||||
m_MoreOptionsParams.bFlatWorld=FALSE;
|
||||
@@ -654,8 +657,13 @@ void UIScene_CreateWorldMenu::handleSliderMove(F64 sliderId, F64 currentValue)
|
||||
case eControl_Difficulty:
|
||||
m_sliderDifficulty.handleSliderMove(value);
|
||||
|
||||
app.SetGameSettings(m_iPad,eGameSetting_Difficulty,value);
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
// 4J Added: Difficulty value 4 = Hardcore (store actual difficulty as Hard, track hardcore separately)
|
||||
s_bHardcore = (value >= 4);
|
||||
app.SetGameSettings(m_iPad, eGameSetting_Difficulty, s_bHardcore ? 3 : value);
|
||||
if (value >= 4)
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ), L"Hardcore");
|
||||
else
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
m_sliderDifficulty.setLabel(TempString);
|
||||
break;
|
||||
}
|
||||
@@ -823,7 +831,7 @@ void UIScene_CreateWorldMenu::checkStateAndStartGame()
|
||||
// 4J Stu - This is a bit messy and is due to the library incorrectly returning false for IsSignedInLive if the npAvailability isn't SCE_OK
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0]=IDS_OK;
|
||||
ui.RequestErrorMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive);
|
||||
ui.RequestAlertMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1113,6 +1121,10 @@ void UIScene_CreateWorldMenu::CreateGame(UIScene_CreateWorldMenu* pClass, DWORD
|
||||
StorageManager.ResetSaveData();
|
||||
// Make our next save default to the name of the level
|
||||
StorageManager.SetSaveTitle((wchar_t *)wWorldName.c_str());
|
||||
#ifdef _WINDOWS64
|
||||
// New world — save folder doesn't exist yet, clear for now (will be set after first autosave)
|
||||
app.SetCurrentSaveFolderName(L"");
|
||||
#endif
|
||||
|
||||
wstring wSeed;
|
||||
if(!pClass->m_MoreOptionsParams.seed.empty() )
|
||||
@@ -1179,7 +1191,9 @@ void UIScene_CreateWorldMenu::CreateGame(UIScene_CreateWorldMenu* pClass, DWORD
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
pMinecraft->skins->selectTexturePackById(pClass->m_MoreOptionsParams.dwTexturePack);
|
||||
|
||||
app.SetGameHostOption(eGameHostOption_Difficulty,Minecraft::GetInstance()->options->difficulty);
|
||||
// 4J Added: If hardcore was selected on difficulty slider, set difficulty to Hard and enable hardcore flag
|
||||
app.SetGameHostOption(eGameHostOption_Difficulty, Minecraft::GetInstance()->options->difficulty);
|
||||
app.SetGameHostOption(eGameHostOption_Hardcore, s_bHardcore ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_FriendsOfFriends,pClass->m_MoreOptionsParams.bAllowFriendsOfFriends);
|
||||
app.SetGameHostOption(eGameHostOption_Gamertags,app.GetGameSettings(pClass->m_iPad,eGameSetting_GamertagsVisible)?1:0);
|
||||
|
||||
|
||||
@@ -3,24 +3,43 @@
|
||||
#include "UIScene_DeathMenu.h"
|
||||
#include "IUIScene_PauseMenu.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#include "..\..\MultiPlayerLevel.h"
|
||||
#include "..\..\MultiplayerLocalPlayer.h"
|
||||
#include "..\..\MinecraftServer.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.level.storage.h"
|
||||
|
||||
UIScene_DeathMenu::UIScene_DeathMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||
{
|
||||
// Setup all the Iggy references we need for this scene
|
||||
initialiseMovie();
|
||||
|
||||
m_buttonRespawn.init(app.GetString(IDS_RESPAWN),eControl_Respawn);
|
||||
m_buttonExitGame.init(app.GetString(IDS_EXIT_GAME),eControl_ExitGame);
|
||||
|
||||
m_labelTitle.setLabel(app.GetString(IDS_YOU_DIED));
|
||||
|
||||
// 4J Added: In hardcore mode, disable respawn and show hardcore death message
|
||||
Minecraft *pMC = Minecraft::GetInstance();
|
||||
bool isHardcore = false;
|
||||
if (pMC != nullptr && pMC->level != nullptr)
|
||||
{
|
||||
isHardcore = pMC->level->getLevelData()->isHardcore();
|
||||
}
|
||||
|
||||
if (isHardcore)
|
||||
{
|
||||
m_buttonRespawn.init(app.GetString(IDS_HARDCORE_DEATH_MESSAGE), eControl_Respawn);
|
||||
m_buttonRespawn.setVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buttonRespawn.init(app.GetString(IDS_RESPAWN), eControl_Respawn);
|
||||
}
|
||||
|
||||
m_bIgnoreInput = false;
|
||||
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
if(pMinecraft != nullptr && pMinecraft->localgameModes[iPad] != nullptr )
|
||||
if(pMC != nullptr && pMC->localgameModes[iPad] != nullptr )
|
||||
{
|
||||
TutorialMode *gameMode = static_cast<TutorialMode *>(pMinecraft->localgameModes[iPad]);
|
||||
TutorialMode *gameMode = static_cast<TutorialMode *>(pMC->localgameModes[iPad]);
|
||||
|
||||
// This just allows it to be shown
|
||||
gameMode->getTutorial()->showTutorialPopup(false);
|
||||
@@ -84,8 +103,16 @@ void UIScene_DeathMenu::handlePress(F64 controlId, F64 childId)
|
||||
switch(static_cast<int>(controlId))
|
||||
{
|
||||
case eControl_Respawn:
|
||||
m_bIgnoreInput = true;
|
||||
app.SetAction(m_iPad,eAppAction_Respawn);
|
||||
{
|
||||
// 4J Added: Safeguard - don't respawn in hardcore mode
|
||||
Minecraft *pMC = Minecraft::GetInstance();
|
||||
if (pMC != nullptr && pMC->level != nullptr && pMC->level->getLevelData()->isHardcore())
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_bIgnoreInput = true;
|
||||
app.SetAction(m_iPad,eAppAction_Respawn);
|
||||
}
|
||||
#ifdef _DURANGO
|
||||
//InputManager.SetEnabledGtcButtons(_360_GTC_MENU|_360_GTC_PAUSE|_360_GTC_VIEW);
|
||||
#endif
|
||||
@@ -109,7 +136,16 @@ void UIScene_DeathMenu::handlePress(F64 controlId, F64 childId)
|
||||
playTime = static_cast<int>(pMinecraft->localplayers[m_iPad]->getSessionTimer());
|
||||
}
|
||||
TelemetryManager->RecordLevelExit(m_iPad, eSen_LevelExitStatus_Failed);
|
||||
|
||||
|
||||
// 4J Added: Hardcore mode — skip save dialog, exit without saving, delete world
|
||||
if (pMinecraft->level != nullptr && pMinecraft->level->getLevelData()->isHardcore() && g_NetworkManager.IsHost())
|
||||
{
|
||||
MinecraftServer::getInstance()->setSaveOnExit(false);
|
||||
MinecraftServer::getInstance()->setDeleteWorldOnExit(true);
|
||||
app.SetAction(m_iPad, eAppAction_ExitWorld);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (_XBOX_ONE) || defined(__ORBIS__)
|
||||
if(g_NetworkManager.IsHost() && StorageManager.GetSaveDisabled())
|
||||
{
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 50
|
||||
#endif
|
||||
|
||||
int UIScene_LoadMenu::m_iDifficultyTitleSettingA[4]=
|
||||
int UIScene_LoadMenu::m_iDifficultyTitleSettingA[5]=
|
||||
{
|
||||
IDS_DIFFICULTY_TITLE_PEACEFUL,
|
||||
IDS_DIFFICULTY_TITLE_EASY,
|
||||
IDS_DIFFICULTY_TITLE_NORMAL,
|
||||
IDS_DIFFICULTY_TITLE_HARD
|
||||
IDS_DIFFICULTY_TITLE_HARD,
|
||||
IDS_GAMEMODE_HARDCORE
|
||||
};
|
||||
|
||||
int UIScene_LoadMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes)
|
||||
@@ -110,6 +111,7 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
|
||||
m_bThumbnailGetFailed = false;
|
||||
m_seed = 0;
|
||||
m_bIsCorrupt = false;
|
||||
m_bHardcore = false;
|
||||
|
||||
m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad);
|
||||
// 4J-PB - read the settings for the online flag. We'll only save this setting if the user changed it.
|
||||
@@ -257,6 +259,30 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
|
||||
m_levelName = wstring(wSaveName);
|
||||
m_labelGameName.init(m_levelName);
|
||||
}
|
||||
if (params->saveDetails != nullptr)
|
||||
{
|
||||
// Set thumbnail name from save filename (needed for texture display in tick)
|
||||
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH];
|
||||
ZeroMemory(wFilename, sizeof(wFilename));
|
||||
mbstowcs(wFilename, params->saveDetails->UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
m_thumbnailName = wFilename;
|
||||
|
||||
if (params->saveDetails->pbThumbnailData && params->saveDetails->dwThumbnailSize > 0)
|
||||
{
|
||||
m_pbThumbnailData = params->saveDetails->pbThumbnailData;
|
||||
m_uiThumbnailSize = params->saveDetails->dwThumbnailSize;
|
||||
m_bSaveThumbnailReady = true;
|
||||
m_bRetrievingSaveThumbnail = false;
|
||||
}
|
||||
|
||||
m_bHardcore = params->saveDetails->isHardcore;
|
||||
if (m_bHardcore)
|
||||
{
|
||||
WCHAR TempString[256];
|
||||
swprintf((WCHAR *)TempString, 256, L"%ls: %ls", app.GetString(IDS_SLIDER_DIFFICULTY), L"Hardcore");
|
||||
m_sliderDifficulty.init(TempString, eControl_Difficulty, 0, 4, 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -546,6 +572,14 @@ void UIScene_LoadMenu::tick()
|
||||
{
|
||||
m_MoreOptionsParams.bAllowFriendsOfFriends = TRUE;
|
||||
}
|
||||
|
||||
m_bHardcore = app.GetGameHostOption(uiHostOptions, eGameHostOption_Hardcore) > 0;
|
||||
if (m_bHardcore)
|
||||
{
|
||||
WCHAR TempString[256];
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ), L"Hardcore");
|
||||
m_sliderDifficulty.init(TempString, eControl_Difficulty, 0, 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
@@ -950,10 +984,15 @@ void UIScene_LoadMenu::handleSliderMove(F64 sliderId, F64 currentValue)
|
||||
switch(static_cast<int>(sliderId))
|
||||
{
|
||||
case eControl_Difficulty:
|
||||
if (m_bHardcore)
|
||||
{
|
||||
m_sliderDifficulty.handleSliderMove(4);
|
||||
break;
|
||||
}
|
||||
m_sliderDifficulty.handleSliderMove(value);
|
||||
|
||||
app.SetGameSettings(m_iPad,eGameSetting_Difficulty,value);
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
m_sliderDifficulty.setLabel(TempString);
|
||||
break;
|
||||
}
|
||||
@@ -1167,7 +1206,7 @@ void UIScene_LoadMenu::LaunchGame(void)
|
||||
#if TO_BE_IMPLEMENTED
|
||||
if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved)
|
||||
{
|
||||
// disable saving
|
||||
// disable saving
|
||||
StorageManager.SetSaveDisabled(true);
|
||||
StorageManager.SetSaveDeviceSelected(m_iPad,false);
|
||||
UINT uiIDA[1];
|
||||
@@ -1580,6 +1619,24 @@ void UIScene_LoadMenu::StartGameFromSave(UIScene_LoadMenu* pClass, DWORD dwLocal
|
||||
|
||||
PSAVE_DETAILS pSaveDetails=StorageManager.ReturnSavesInfo();
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
// 4J Added: Store save folder name for potential hardcore world deletion
|
||||
app.DebugPrintf("StartGameFromSave: pSaveDetails=%p, levelGen=%p, saveInfoIndex=%d\n", pSaveDetails, pClass->m_levelGen, pClass->m_iSaveGameInfoIndex);
|
||||
if (pSaveDetails != nullptr && pClass->m_levelGen == nullptr)
|
||||
{
|
||||
app.DebugPrintf("StartGameFromSave: UTF8SaveFilename='%s'\n", pSaveDetails->SaveInfoA[(int)pClass->m_iSaveGameInfoIndex].UTF8SaveFilename);
|
||||
wchar_t wFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
mbstowcs(wFolder, pSaveDetails->SaveInfoA[(int)pClass->m_iSaveGameInfoIndex].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
app.SetCurrentSaveFolderName(wFolder);
|
||||
app.DebugPrintf("StartGameFromSave: stored folder name '%ls'\n", wFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf("StartGameFromSave: no save details or is levelGen, clearing folder name\n");
|
||||
app.SetCurrentSaveFolderName(L"");
|
||||
}
|
||||
#endif
|
||||
|
||||
NetworkGameInitData *param = new NetworkGameInitData();
|
||||
param->seed = pClass->m_seed;
|
||||
param->saveData = nullptr;
|
||||
@@ -1612,6 +1669,7 @@ void UIScene_LoadMenu::StartGameFromSave(UIScene_LoadMenu* pClass, DWORD dwLocal
|
||||
app.SetGameHostOption(eGameHostOption_DoTileDrops, pClass->m_MoreOptionsParams.bDoTileDrops);
|
||||
app.SetGameHostOption(eGameHostOption_NaturalRegeneration, pClass->m_MoreOptionsParams.bNaturalRegeneration);
|
||||
app.SetGameHostOption(eGameHostOption_DoDaylightCycle, pClass->m_MoreOptionsParams.bDoDaylightCycle);
|
||||
app.SetGameHostOption(eGameHostOption_Hardcore, pClass->m_bHardcore ? 1 : 0);
|
||||
|
||||
#ifdef _LARGE_WORLDS
|
||||
app.SetGameHostOption(eGameHostOption_WorldSize, pClass->m_MoreOptionsParams.worldSize+1 ); // 0 is GAME_HOST_OPTION_WORLDSIZE_UNKNOWN
|
||||
|
||||
@@ -15,7 +15,7 @@ private:
|
||||
eControl_OnlineGame,
|
||||
};
|
||||
|
||||
static int m_iDifficultyTitleSettingA[4];
|
||||
static int m_iDifficultyTitleSettingA[5];
|
||||
|
||||
UIControl m_controlMainPanel;
|
||||
UIControl_Label m_labelGameName, m_labelSeed, m_labelCreatedMode;
|
||||
@@ -71,6 +71,7 @@ private:
|
||||
wstring m_thumbnailName;
|
||||
|
||||
bool m_bRebuildTouchBoxes;
|
||||
bool m_bHardcore;
|
||||
public:
|
||||
UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLayer);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "..\..\..\Minecraft.World\NbtIo.h"
|
||||
#include "..\..\..\Minecraft.World\compression.h"
|
||||
|
||||
static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
|
||||
static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardcore = nullptr)
|
||||
{
|
||||
// Check for a worldname.txt sidecar written by the rename feature first
|
||||
size_t slashPos = filePath.rfind(L'\\');
|
||||
@@ -124,7 +124,11 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
|
||||
{
|
||||
CompoundTag *dataTag = root->getCompound(L"Data");
|
||||
if (dataTag != nullptr)
|
||||
{
|
||||
result = dataTag->getString(L"LevelName");
|
||||
if (outHardcore)
|
||||
*outHardcore = dataTag->getBoolean(L"hardcore");
|
||||
}
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
@@ -775,7 +779,9 @@ void UIScene_LoadOrJoinMenu::tick()
|
||||
ZeroMemory(wFilename, sizeof(wFilename));
|
||||
mbstowcs(wFilename, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\saveData.ms");
|
||||
wstring levelName = ReadLevelNameFromSaveFile(filePath);
|
||||
bool saveHardcore = false;
|
||||
wstring levelName = ReadLevelNameFromSaveFile(filePath, &saveHardcore);
|
||||
m_saveDetails[i].isHardcore = saveHardcore;
|
||||
if (!levelName.empty())
|
||||
{
|
||||
m_buttonListSaves.addItem(levelName, wstring(L""));
|
||||
|
||||
@@ -247,11 +247,14 @@ typedef struct _SaveListDetails
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool isHardcore;
|
||||
|
||||
_SaveListDetails()
|
||||
{
|
||||
saveId = 0;
|
||||
pbThumbnailData = nullptr;
|
||||
dwThumbnailSize = 0;
|
||||
isHardcore = false;
|
||||
#ifdef _DURANGO
|
||||
ZeroMemory(UTF16SaveName,sizeof(wchar_t)*128);
|
||||
ZeroMemory(UTF16SaveFilename,sizeof(wchar_t)*MAX_SAVEFILENAME_LENGTH);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "..\..\..\Minecraft.World\Entity.h"
|
||||
#include "..\..\..\Minecraft.Client\MultiplayerLocalPlayer.h"
|
||||
#include "..\..\..\Minecraft.World\Level.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.level.storage.h"
|
||||
#include "..\..\..\Minecraft.World\ChunkSource.h"
|
||||
#include "..\..\..\Minecraft.Client\ProgressRenderer.h"
|
||||
#include "..\..\..\Minecraft.Client\GameRenderer.h"
|
||||
@@ -18,6 +19,7 @@
|
||||
#include "..\..\..\Minecraft.World\Pos.h"
|
||||
#include "..\..\..\Minecraft.World\Dimension.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#include "..\..\MinecraftServer.h"
|
||||
#include "..\..\Options.h"
|
||||
#include "..\..\LocalPlayer.h"
|
||||
#include "..\..\..\Minecraft.World\compression.h"
|
||||
@@ -37,9 +39,26 @@ HRESULT CScene_Death::OnInit( XUIMessageInit* pInitData, BOOL& bHandled )
|
||||
}
|
||||
|
||||
XuiControlSetText(m_Title,app.GetString(IDS_YOU_DIED));
|
||||
XuiControlSetText(m_Buttons[BUTTON_DEATH_RESPAWN],app.GetString(IDS_RESPAWN));
|
||||
XuiControlSetText(m_Buttons[BUTTON_DEATH_EXITGAME],app.GetString(IDS_EXIT_GAME));
|
||||
|
||||
// 4J Added: In hardcore mode, disable respawn and show hardcore death message
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
bool isHardcore = false;
|
||||
if (pMinecraft != nullptr && pMinecraft->level != nullptr)
|
||||
{
|
||||
isHardcore = pMinecraft->level->getLevelData()->isHardcore();
|
||||
}
|
||||
|
||||
if (isHardcore)
|
||||
{
|
||||
XuiControlSetText(m_Buttons[BUTTON_DEATH_RESPAWN], app.GetString(IDS_HARDCORE_DEATH_MESSAGE));
|
||||
XuiElementSetShow(m_Buttons[BUTTON_DEATH_RESPAWN], FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
XuiControlSetText(m_Buttons[BUTTON_DEATH_RESPAWN], app.GetString(IDS_RESPAWN));
|
||||
}
|
||||
|
||||
// Display the tooltips
|
||||
ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT);
|
||||
|
||||
@@ -110,7 +129,16 @@ HRESULT CScene_Death::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNoti
|
||||
playTime = static_cast<int>(pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer());
|
||||
}
|
||||
TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Failed);
|
||||
|
||||
|
||||
// 4J Added: Hardcore mode — skip save dialog, exit without saving, delete world
|
||||
if (pMinecraft->level != nullptr && pMinecraft->level->getLevelData()->isHardcore() && g_NetworkManager.IsHost())
|
||||
{
|
||||
MinecraftServer::getInstance()->setSaveOnExit(false);
|
||||
MinecraftServer::getInstance()->setDeleteWorldOnExit(true);
|
||||
app.SetAction(pNotifyPressData->UserIndex, eAppAction_ExitWorld);
|
||||
break;
|
||||
}
|
||||
|
||||
if(StorageManager.GetSaveDisabled())
|
||||
{
|
||||
uiIDA[0]=IDS_CONFIRM_CANCEL;
|
||||
@@ -172,6 +200,12 @@ HRESULT CScene_Death::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNoti
|
||||
break;
|
||||
case BUTTON_DEATH_RESPAWN:
|
||||
{
|
||||
// 4J Added: Safeguard - don't respawn in hardcore mode
|
||||
Minecraft *pMC = Minecraft::GetInstance();
|
||||
if (pMC != nullptr && pMC->level != nullptr && pMC->level->getLevelData()->isHardcore())
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_bIgnoreInput = true;
|
||||
app.SetAction(pNotifyPressData->UserIndex,eAppAction_Respawn);
|
||||
}
|
||||
|
||||
@@ -854,6 +854,210 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
||||
// font.draw(str, x + 1, y, 0xffffff);
|
||||
// }
|
||||
|
||||
#ifndef _FINAL_BUILD
|
||||
MemSect(31);
|
||||
|
||||
// temporarily render overlay at all times so version is more obvious in bug reports
|
||||
// we can turn this off once things stabilize
|
||||
if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
|
||||
{
|
||||
const int debugLeft = 1;
|
||||
const int debugTop = 1;
|
||||
const float maxContentWidth = 1200.f;
|
||||
const float maxContentHeight = 420.f;
|
||||
float scale = static_cast<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
|
||||
|
||||
@@ -561,6 +561,7 @@ MinecraftServer::MinecraftServer()
|
||||
m_serverPausedEvent = new C4JThread::Event;
|
||||
|
||||
m_saveOnExit = false;
|
||||
m_deleteWorldOnExit = false;
|
||||
m_suspending = false;
|
||||
|
||||
m_ugcPlayersVersion = 0;
|
||||
@@ -887,6 +888,15 @@ bool MinecraftServer::loadLevel(LevelStorageSource *storageSource, const wstring
|
||||
// }
|
||||
ProgressRenderer *mcprogress = Minecraft::GetInstance()->progressRenderer;
|
||||
|
||||
// 4J Added - store save folder name for potential hardcore world deletion
|
||||
{
|
||||
char szSaveFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
StorageManager.GetSaveUniqueFilename(szSaveFolder);
|
||||
wchar_t wSaveFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
mbstowcs(wSaveFolder, szSaveFolder, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
m_saveFolderName = wSaveFolder;
|
||||
}
|
||||
|
||||
// 4J TODO - free levels here if there are already some?
|
||||
levels = ServerLevelArray(3);
|
||||
|
||||
@@ -1642,7 +1652,7 @@ bool MinecraftServer::isNetherEnabled()
|
||||
|
||||
bool MinecraftServer::isHardcore()
|
||||
{
|
||||
return false;
|
||||
return app.GetGameHostOption(eGameHostOption_Hardcore) > 0;
|
||||
}
|
||||
|
||||
int MinecraftServer::getOperatorUserPermissionLevel()
|
||||
|
||||
@@ -265,6 +265,8 @@ private:
|
||||
private:
|
||||
// 4J Added
|
||||
bool m_saveOnExit;
|
||||
bool m_deleteWorldOnExit; // 4J Added - for hardcore mode world deletion
|
||||
wstring m_saveFolderName; // 4J Added - stored for hardcore world deletion
|
||||
bool m_suspending;
|
||||
|
||||
public:
|
||||
@@ -278,6 +280,9 @@ public:
|
||||
void chunkPacketManagement_PostTick();
|
||||
|
||||
void setSaveOnExit(bool save) { m_saveOnExit = save; s_bSaveOnExitAnswered = true; }
|
||||
void setDeleteWorldOnExit(bool del) { m_deleteWorldOnExit = del; }
|
||||
bool getDeleteWorldOnExit() const { return m_deleteWorldOnExit; }
|
||||
const wstring& getSaveFolderName() const { return m_saveFolderName; }
|
||||
void Suspend();
|
||||
bool IsSuspending();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ConsoleInputSource.h"
|
||||
#include "..\Minecraft.World\PacketListener.h"
|
||||
#include "..\Minecraft.World\JavaIntHash.h"
|
||||
#include <atomic>
|
||||
|
||||
class MinecraftServer;
|
||||
class Connection;
|
||||
@@ -130,8 +131,8 @@ public:
|
||||
|
||||
void setShowOnMaps(bool bVal);
|
||||
|
||||
void setWasKicked() { m_bWasKicked = true; }
|
||||
bool getWasKicked() { return m_bWasKicked; }
|
||||
void setWasKicked() { m_bWasKicked.store(true); }
|
||||
bool getWasKicked() { return m_bWasKicked.load(); }
|
||||
|
||||
// 4J Added
|
||||
bool hasClientTickedOnce() { return m_bHasClientTickedOnce; }
|
||||
@@ -140,5 +141,5 @@ private:
|
||||
bool m_bCloseOnTick;
|
||||
vector<wstring> m_texturesRequested;
|
||||
|
||||
bool m_bWasKicked;
|
||||
std::atomic<bool> m_bWasKicked{false};
|
||||
};
|
||||
@@ -67,6 +67,7 @@ PlayerList::PlayerList(MinecraftServer *server)
|
||||
int rawMax = server->settings->getInt(L"max-players", 8);
|
||||
maxPlayers = static_cast<unsigned int>(Mth::clamp(rawMax, 1, MINECRAFT_NET_MAX_PLAYERS));
|
||||
doWhiteList = false;
|
||||
InitializeCriticalSection(&m_banCS);
|
||||
InitializeCriticalSection(&m_kickPlayersCS);
|
||||
InitializeCriticalSection(&m_closePlayersCS);
|
||||
}
|
||||
@@ -80,6 +81,7 @@ PlayerList::~PlayerList()
|
||||
player->gameMode = nullptr;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&m_banCS);
|
||||
DeleteCriticalSection(&m_kickPlayersCS);
|
||||
DeleteCriticalSection(&m_closePlayersCS);
|
||||
}
|
||||
@@ -271,7 +273,8 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
|
||||
static_cast<BYTE>(playerIndex), level->useNewSeaLevel(),
|
||||
player->getAllPlayerGamePrivileges(),
|
||||
level->getLevelData()->getXZSize(),
|
||||
level->getLevelData()->getHellScale()));
|
||||
level->getLevelData()->getHellScale(),
|
||||
level->getLevelData()->isHardcore()));
|
||||
playerConnection->send(std::make_shared<SetSpawnPositionPacket>(spawnPos->x, spawnPos->y, spawnPos->z));
|
||||
playerConnection->send(std::make_shared<PlayerAbilitiesPacket>(&player->abilities));
|
||||
playerConnection->send(std::make_shared<SetCarriedItemPacket>(player->inventory->selected));
|
||||
@@ -702,6 +705,13 @@ shared_ptr<ServerPlayer> PlayerList::respawn(shared_ptr<ServerPlayer> serverPlay
|
||||
// necessary)
|
||||
updatePlayerGameMode(player, serverPlayer, level);
|
||||
|
||||
// 4J Added: Hardcore mode — force Adventure mode on respawn
|
||||
if (server->getLevel(0)->getLevelData()->isHardcore())
|
||||
{
|
||||
player->gameMode->setGameModeForPlayer(GameType::ADVENTURE);
|
||||
player->connection->send(std::make_shared<GameEventPacket>(GameEventPacket::CHANGE_GAME_MODE, GameType::ADVENTURE->getId()));
|
||||
}
|
||||
|
||||
if(serverPlayer->wonGame && targetDimension == oldDimension && serverPlayer->getHealth() > 0)
|
||||
{
|
||||
// If the player is still alive and respawning to the same dimension, they are just being added back from someone else viewing the Win screen
|
||||
@@ -739,7 +749,7 @@ shared_ptr<ServerPlayer> PlayerList::respawn(shared_ptr<ServerPlayer> serverPlay
|
||||
|
||||
player->connection->send( std::make_shared<RespawnPacket>( static_cast<char>(player->dimension), player->level->getSeed(), player->level->getMaxBuildHeight(),
|
||||
player->gameMode->getGameModeForPlayer(), level->difficulty, level->getLevelData()->getGenerator(),
|
||||
player->level->useNewSeaLevel(), player->entityId, level->getLevelData()->getXZSize(), level->getLevelData()->getHellScale() ) );
|
||||
player->level->useNewSeaLevel(), player->entityId, level->getLevelData()->getXZSize(), level->getLevelData()->getHellScale(), level->getLevelData()->isHardcore() ) );
|
||||
player->connection->teleport(player->x, player->y, player->z, player->yRot, player->xRot);
|
||||
player->connection->send( std::make_shared<SetExperiencePacket>( player->experienceProgress, player->totalExperience, player->experienceLevel) );
|
||||
|
||||
@@ -856,7 +866,7 @@ void PlayerList::toggleDimension(shared_ptr<ServerPlayer> player, int targetDime
|
||||
|
||||
player->connection->send(std::make_shared<RespawnPacket>(static_cast<char>(player->dimension), newLevel->getSeed(), newLevel->getMaxBuildHeight(),
|
||||
player->gameMode->getGameModeForPlayer(), newLevel->difficulty, newLevel->getLevelData()->getGenerator(),
|
||||
newLevel->useNewSeaLevel(), player->entityId, newLevel->getLevelData()->getXZSize(), newLevel->getLevelData()->getHellScale()));
|
||||
newLevel->useNewSeaLevel(), player->entityId, newLevel->getLevelData()->getXZSize(), newLevel->getLevelData()->getHellScale(), newLevel->getLevelData()->isHardcore()));
|
||||
|
||||
oldLevel->removeEntityImmediately(player);
|
||||
player->removed = false;
|
||||
@@ -1670,6 +1680,7 @@ bool PlayerList::isXuidBanned(PlayerUID xuid)
|
||||
|
||||
bool banned = false;
|
||||
|
||||
EnterCriticalSection(&m_banCS);
|
||||
for(PlayerUID it : m_bannedXuids)
|
||||
{
|
||||
if( ProfileManager.AreXUIDSEqual( xuid, it ) )
|
||||
@@ -1678,6 +1689,7 @@ bool PlayerList::isXuidBanned(PlayerUID xuid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&m_banCS);
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!banned && g_Win64DedicatedServer)
|
||||
@@ -1689,6 +1701,34 @@ bool PlayerList::isXuidBanned(PlayerUID xuid)
|
||||
return banned;
|
||||
}
|
||||
|
||||
void PlayerList::banXuid(PlayerUID xuid)
|
||||
{
|
||||
// 4J Added - for hardcore mode ban-on-death
|
||||
// Ban a player's XUID. Used when a player dies in a hardcore multiplayer world.
|
||||
if(xuid == INVALID_XUID) return;
|
||||
|
||||
EnterCriticalSection(&m_banCS);
|
||||
|
||||
// Check if already banned
|
||||
bool alreadyBanned = false;
|
||||
for(PlayerUID it : m_bannedXuids)
|
||||
{
|
||||
if( ProfileManager.AreXUIDSEqual( xuid, it ) )
|
||||
{
|
||||
alreadyBanned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!alreadyBanned)
|
||||
{
|
||||
m_bannedXuids.push_back(xuid);
|
||||
app.DebugPrintf("PlayerList::banXuid - Player XUID banned for hardcore death\n");
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&m_banCS);
|
||||
}
|
||||
|
||||
// AP added for Vita so the range can be increased once the level starts
|
||||
void PlayerList::setViewDistance(int newViewDistance)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ private:
|
||||
|
||||
// 4J Added
|
||||
vector<PlayerUID> m_bannedXuids;
|
||||
CRITICAL_SECTION m_banCS; // 4J Added - protects m_bannedXuids for concurrent access
|
||||
deque<BYTE> m_smallIdsToKick;
|
||||
CRITICAL_SECTION m_kickPlayersCS;
|
||||
deque<BYTE> m_smallIdsToClose;
|
||||
@@ -135,6 +136,7 @@ public:
|
||||
void closePlayerConnectionBySmallId(BYTE networkSmallId);
|
||||
void queueSmallIdForRecycle(BYTE smallId);
|
||||
bool isXuidBanned(PlayerUID xuid);
|
||||
void banXuid(PlayerUID xuid); // 4J Added - for hardcore mode ban-on-death
|
||||
// AP added for Vita so the range can be increased once the level starts
|
||||
void setViewDistance(int newViewDistance);
|
||||
};
|
||||
|
||||
@@ -303,6 +303,12 @@ void SelectWorldScreen::WorldSelectionList::renderItem(int i, int x, int y, int
|
||||
info = parent->conversionLang + L" " + info;
|
||||
}
|
||||
|
||||
// 4J Added: Show [Hardcore] badge for hardcore worlds
|
||||
if (levelSummary->isHardcore())
|
||||
{
|
||||
name = name + L" [Hardcore]";
|
||||
}
|
||||
|
||||
parent->drawString(parent->font, name, x + 2, y + 1, 0xffffff);
|
||||
parent->drawString(parent->font, id, x + 2, y + 12, 0x808080);
|
||||
parent->drawString(parent->font, info, x + 2, y + 12 + 10, 0x808080);
|
||||
|
||||
@@ -564,6 +564,17 @@ void ServerPlayer::die(DamageSource *source)
|
||||
{
|
||||
server->getPlayers()->broadcastAll(getCombatTracker()->getDeathMessagePacket());
|
||||
|
||||
// 4J Added: Hardcore mode — switch to Adventure mode on death (can look but not break/place blocks)
|
||||
if (level->getLevelData()->isHardcore())
|
||||
{
|
||||
setGameMode(GameType::ADVENTURE);
|
||||
|
||||
// Ban this player's XUID and force-save so the host
|
||||
// cannot circumvent the death by quitting without saving.
|
||||
server->getPlayers()->banXuid(getOnlineXuid());
|
||||
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_SaveGame);
|
||||
}
|
||||
|
||||
if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY))
|
||||
{
|
||||
inventory->dropAll();
|
||||
@@ -1604,9 +1615,9 @@ bool ServerPlayer::hasPermission(EGameCommand command)
|
||||
//
|
||||
// // 4J - Don't need
|
||||
// //if (server.isSingleplayer() && server.getSingleplayerName().equals(name))
|
||||
// //{
|
||||
/// //{
|
||||
// // server.setDifficulty(packet.getDifficulty());
|
||||
// //}
|
||||
/// //}
|
||||
//}
|
||||
|
||||
int ServerPlayer::getViewDistance()
|
||||
|
||||
@@ -2289,3 +2289,11 @@
|
||||
#define IDS_RICHPRESENCESTATE_BREWING 2283
|
||||
#define IDS_RICHPRESENCESTATE_ANVIL 2284
|
||||
#define IDS_RICHPRESENCESTATE_TRADING 2285
|
||||
#define IDS_GAMEMODE_HARDCORE 2286
|
||||
#define IDS_HARDCORE 2287
|
||||
#define IDS_HARDCORE_TOOLTIP 2288
|
||||
#define IDS_HARDCORE_WARNING_TITLE 2289
|
||||
#define IDS_HARDCORE_WARNING_TEXT 2290
|
||||
#define IDS_HARDCORE_DEATH_MESSAGE 2291
|
||||
#define IDS_LABEL_HARDCORE 2292
|
||||
#define IDS_GAMEOPTION_HARDCORE 2293
|
||||
@@ -838,6 +838,51 @@ int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes)
|
||||
{
|
||||
ConsoleSaveFile *pClass=static_cast<ConsoleSaveFile *>(lpParam);
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
// 4J Added: After save completes, capture the save folder name for hardcore world deletion
|
||||
if (bRes && app.GetCurrentSaveFolderName().empty())
|
||||
{
|
||||
// Try 1: Ask the library for the folder name
|
||||
char szSaveFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
if (StorageManager.GetSaveUniqueFilename(szSaveFolder) && szSaveFolder[0] != '\0')
|
||||
{
|
||||
wchar_t wFolder[MAX_SAVEFILENAME_LENGTH] = {};
|
||||
mbstowcs(wFolder, szSaveFolder, MAX_SAVEFILENAME_LENGTH - 1);
|
||||
app.SetCurrentSaveFolderName(wFolder);
|
||||
app.DebugPrintf("SaveSaveDataCallback: captured save folder '%s'\n", szSaveFolder);
|
||||
}
|
||||
// Try 2: Scan GameHDD for the newest folder — right after save, it's guaranteed to be ours
|
||||
if (app.GetCurrentSaveFolderName().empty())
|
||||
{
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = FindFirstFileW(L"Windows64\\GameHDD\\*", &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FILETIME newestTime = {};
|
||||
wchar_t newestFolder[MAX_PATH] = {};
|
||||
do
|
||||
{
|
||||
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0)
|
||||
{
|
||||
if (CompareFileTime(&fd.ftLastWriteTime, &newestTime) > 0)
|
||||
{
|
||||
newestTime = fd.ftLastWriteTime;
|
||||
wcscpy_s(newestFolder, MAX_PATH, fd.cFileName);
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(hFind, &fd));
|
||||
FindClose(hFind);
|
||||
if (newestFolder[0] != L'\0')
|
||||
{
|
||||
app.SetCurrentSaveFolderName(newestFolder);
|
||||
app.DebugPrintf("SaveSaveDataCallback: captured save folder via scan '%ls'\n", newestFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
#ifdef _XBOX_ONE
|
||||
eDisconnect_ExitedGame,
|
||||
#endif
|
||||
eDisconnect_HardcoreDeath, // 4J Added - for hardcore mode multiplayer ban-on-death
|
||||
};
|
||||
|
||||
// 4J Stu - The reason was a string, but we need to send a non-locale specific reason
|
||||
@@ -71,3 +72,4 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ LoginPacket::LoginPacket()
|
||||
m_uiGamePrivileges = 0;
|
||||
m_xzSize = LEVEL_MAX_WIDTH;
|
||||
m_hellScale = HELL_LEVEL_MAX_SCALE;
|
||||
m_isHardcore = false;
|
||||
}
|
||||
|
||||
// Client -> Server
|
||||
@@ -63,10 +64,11 @@ LoginPacket::LoginPacket(const wstring& userName, int clientVersion, PlayerUID o
|
||||
m_uiGamePrivileges = 0;
|
||||
m_xzSize = LEVEL_MAX_WIDTH;
|
||||
m_hellScale = HELL_LEVEL_MAX_SCALE;
|
||||
m_isHardcore = false;
|
||||
}
|
||||
|
||||
// Server -> Client
|
||||
LoginPacket::LoginPacket(const wstring& userName, int clientVersion, LevelType *pLevelType, int64_t seed, int gameType, char dimension, BYTE mapHeight, BYTE maxPlayers, char difficulty, INT multiplayerInstanceId, BYTE playerIndex, bool newSeaLevel, unsigned int uiGamePrivileges, int xzSize, int hellScale)
|
||||
LoginPacket::LoginPacket(const wstring& userName, int clientVersion, LevelType *pLevelType, int64_t seed, int gameType, char dimension, BYTE mapHeight, BYTE maxPlayers, char difficulty, INT multiplayerInstanceId, BYTE playerIndex, bool newSeaLevel, unsigned int uiGamePrivileges, int xzSize, int hellScale, bool isHardcore)
|
||||
{
|
||||
this->userName = userName;
|
||||
this->clientVersion = clientVersion;
|
||||
@@ -92,6 +94,7 @@ LoginPacket::LoginPacket(const wstring& userName, int clientVersion, LevelType *
|
||||
m_uiGamePrivileges = uiGamePrivileges;
|
||||
m_xzSize = xzSize;
|
||||
m_hellScale = hellScale;
|
||||
m_isHardcore = isHardcore;
|
||||
}
|
||||
|
||||
void LoginPacket::read(DataInputStream *dis) //throws IOException
|
||||
@@ -106,6 +109,8 @@ void LoginPacket::read(DataInputStream *dis) //throws IOException
|
||||
}
|
||||
seed = dis->readLong();
|
||||
gameType = dis->readInt();
|
||||
m_isHardcore = (gameType & 0x8) != 0;
|
||||
gameType = gameType & ~0x8;
|
||||
dimension = dis->readByte();
|
||||
mapHeight = dis->readByte();
|
||||
maxPlayers = dis->readByte();
|
||||
@@ -144,7 +149,7 @@ void LoginPacket::write(DataOutputStream *dos) //throws IOException
|
||||
writeUtf(m_pLevelType->getGeneratorName(), dos);
|
||||
}
|
||||
dos->writeLong(seed);
|
||||
dos->writeInt(gameType);
|
||||
dos->writeInt(gameType | (m_isHardcore ? 0x8 : 0));
|
||||
dos->writeByte(dimension);
|
||||
dos->writeByte(mapHeight);
|
||||
dos->writeByte(maxPlayers);
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
unsigned int m_uiGamePrivileges;
|
||||
int m_xzSize; // 4J Added
|
||||
int m_hellScale; // 4J Added
|
||||
bool m_isHardcore; // 4J Added - for hardcore mode
|
||||
|
||||
// 1.8.2
|
||||
int gameType;
|
||||
@@ -31,7 +32,7 @@ public:
|
||||
BYTE maxPlayers;
|
||||
|
||||
LoginPacket();
|
||||
LoginPacket(const wstring& userName, int clientVersion, LevelType *pLevelType, int64_t seed, int gameType, char dimension, BYTE mapHeight, BYTE maxPlayers, char difficulty, INT m_multiplayerInstanceId, BYTE playerIndex, bool newSeaLevel, unsigned int uiGamePrivileges, int xzSize, int hellScale); // Server -> Client
|
||||
LoginPacket(const wstring& userName, int clientVersion, LevelType *pLevelType, int64_t seed, int gameType, char dimension, BYTE mapHeight, BYTE maxPlayers, char difficulty, INT m_multiplayerInstanceId, BYTE playerIndex, bool newSeaLevel, unsigned int uiGamePrivileges, int xzSize, int hellScale, bool isHardcore = false); // Server -> Client
|
||||
LoginPacket(const wstring& userName, int clientVersion, PlayerUID offlineXuid, PlayerUID onlineXuid, bool friendsOnlyUGC, DWORD ugcPlayersVersion, DWORD skinId, DWORD capeId, bool isGuest); // Client -> Server
|
||||
|
||||
virtual void read(DataInputStream *dis);
|
||||
|
||||
@@ -17,9 +17,10 @@ RespawnPacket::RespawnPacket()
|
||||
m_newEntityId = 0;
|
||||
m_xzSize = LEVEL_MAX_WIDTH;
|
||||
m_hellScale = HELL_LEVEL_MAX_SCALE;
|
||||
m_isHardcore = false;
|
||||
}
|
||||
|
||||
RespawnPacket::RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale)
|
||||
RespawnPacket::RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale, bool isHardcore)
|
||||
{
|
||||
this->dimension = dimension;
|
||||
this->mapSeed = mapSeed;
|
||||
@@ -31,6 +32,7 @@ RespawnPacket::RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, Gam
|
||||
this->m_newEntityId = newEntityId;
|
||||
m_xzSize = xzSize;
|
||||
m_hellScale = hellScale;
|
||||
m_isHardcore = isHardcore;
|
||||
app.DebugPrintf("RespawnPacket - Difficulty = %d\n",difficulty);
|
||||
|
||||
}
|
||||
@@ -43,7 +45,9 @@ void RespawnPacket::handle(PacketListener *listener)
|
||||
void RespawnPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
dimension = dis->readByte();
|
||||
playerGameType = GameType::byId(dis->readByte());
|
||||
int rawGameType = dis->readByte();
|
||||
m_isHardcore = (rawGameType & 0x8) != 0;
|
||||
playerGameType = GameType::byId(rawGameType & ~0x8);
|
||||
mapHeight = dis->readShort();
|
||||
wstring typeName = readUtf(dis, 16);
|
||||
m_pLevelType = LevelType::getLevelType(typeName);
|
||||
@@ -66,7 +70,7 @@ void RespawnPacket::read(DataInputStream *dis) //throws IOException
|
||||
void RespawnPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeByte(dimension);
|
||||
dos->writeByte(playerGameType->getId());
|
||||
dos->writeByte(playerGameType->getId() | (m_isHardcore ? 0x8 : 0));
|
||||
dos->writeShort(mapHeight);
|
||||
if (m_pLevelType == nullptr)
|
||||
{
|
||||
|
||||
@@ -19,9 +19,10 @@ public:
|
||||
int m_newEntityId;
|
||||
int m_xzSize; // 4J Added
|
||||
int m_hellScale; // 4J Added
|
||||
bool m_isHardcore; // 4J Added - for hardcore mode
|
||||
|
||||
RespawnPacket();
|
||||
RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale);
|
||||
RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale, bool isHardcore = false);
|
||||
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual void read(DataInputStream *dis);
|
||||
|
||||
Reference in New Issue
Block a user