Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 49c1f2c1da | |||
| 43d520f692 | |||
| 0b0d74a638 | |||
| b27cb536a5 | |||
| 15ea3dc85c | |||
| 9fde19eca0 | |||
| e9f5b4b6f0 | |||
| 7b643cdd75 |
@@ -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, packet->m_isHardcore, 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, false, 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, packet->m_isHardcore, 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, false, 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, packet->m_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, minecraft->level->getLevelData()->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,7 +45,6 @@
|
||||
#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,7 +648,6 @@ 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,16 +8084,6 @@ 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;
|
||||
@@ -8195,9 +8185,6 @@ 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,10 +805,6 @@ 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:
|
||||
@@ -830,7 +826,6 @@ 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];
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -410,72 +410,11 @@ 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;
|
||||
|
||||
@@ -686,17 +625,6 @@ 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();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "UI.h"
|
||||
#include "UIControl_TextInput.h"
|
||||
#include "..\..\Screen.h"
|
||||
|
||||
UIControl_TextInput::UIControl_TextInput()
|
||||
{
|
||||
@@ -211,6 +212,31 @@ UIControl_TextInput::EDirectEditResult UIControl_TextInput::tickDirectEdit()
|
||||
}
|
||||
}
|
||||
|
||||
// Paste from clipboard
|
||||
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
|
||||
{
|
||||
wstring pasted = Screen::getClipboard();
|
||||
wstring sanitized;
|
||||
sanitized.reserve(pasted.length());
|
||||
|
||||
for (wchar_t pc : pasted)
|
||||
{
|
||||
if (pc >= 0x20) // Keep printable characters
|
||||
{
|
||||
if (m_iCharLimit > 0 && (m_editBuffer.length() + sanitized.length()) >= (size_t)m_iCharLimit)
|
||||
break;
|
||||
sanitized += pc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sanitized.empty())
|
||||
{
|
||||
m_editBuffer.insert(m_iCursorPos, sanitized);
|
||||
m_iCursorPos += (int)sanitized.length();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Arrow keys, Home, End, Delete for cursor movement
|
||||
if (g_KBMInput.IsKeyPressed(VK_LEFT) && m_iCursorPos > 0)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#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,
|
||||
@@ -61,9 +59,8 @@ 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,4,app.GetGameSettings(m_iPad,eGameSetting_Difficulty));
|
||||
m_sliderDifficulty.init(TempString,eControl_Difficulty,0,3,app.GetGameSettings(m_iPad,eGameSetting_Difficulty));
|
||||
|
||||
s_bHardcore = false;
|
||||
m_MoreOptionsParams.bGenerateOptions=TRUE;
|
||||
m_MoreOptionsParams.bStructures=TRUE;
|
||||
m_MoreOptionsParams.bFlatWorld=FALSE;
|
||||
@@ -657,13 +654,8 @@ void UIScene_CreateWorldMenu::handleSliderMove(F64 sliderId, F64 currentValue)
|
||||
case eControl_Difficulty:
|
||||
m_sliderDifficulty.handleSliderMove(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]));
|
||||
app.SetGameSettings(m_iPad,eGameSetting_Difficulty,value);
|
||||
swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[value]));
|
||||
m_sliderDifficulty.setLabel(TempString);
|
||||
break;
|
||||
}
|
||||
@@ -831,7 +823,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.RequestAlertMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive);
|
||||
ui.RequestErrorMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1121,10 +1113,6 @@ 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() )
|
||||
@@ -1191,9 +1179,7 @@ void UIScene_CreateWorldMenu::CreateGame(UIScene_CreateWorldMenu* pClass, DWORD
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
pMinecraft->skins->selectTexturePackById(pClass->m_MoreOptionsParams.dwTexturePack);
|
||||
|
||||
// 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_Difficulty,Minecraft::GetInstance()->options->difficulty);
|
||||
app.SetGameHostOption(eGameHostOption_FriendsOfFriends,pClass->m_MoreOptionsParams.bAllowFriendsOfFriends);
|
||||
app.SetGameHostOption(eGameHostOption_Gamertags,app.GetGameSettings(pClass->m_iPad,eGameSetting_GamertagsVisible)?1:0);
|
||||
|
||||
|
||||
@@ -3,43 +3,24 @@
|
||||
#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;
|
||||
|
||||
if(pMC != nullptr && pMC->localgameModes[iPad] != nullptr )
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
if(pMinecraft != nullptr && pMinecraft->localgameModes[iPad] != nullptr )
|
||||
{
|
||||
TutorialMode *gameMode = static_cast<TutorialMode *>(pMC->localgameModes[iPad]);
|
||||
TutorialMode *gameMode = static_cast<TutorialMode *>(pMinecraft->localgameModes[iPad]);
|
||||
|
||||
// This just allows it to be shown
|
||||
gameMode->getTutorial()->showTutorialPopup(false);
|
||||
@@ -103,16 +84,8 @@ void UIScene_DeathMenu::handlePress(F64 controlId, F64 childId)
|
||||
switch(static_cast<int>(controlId))
|
||||
{
|
||||
case eControl_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);
|
||||
}
|
||||
m_bIgnoreInput = true;
|
||||
app.SetAction(m_iPad,eAppAction_Respawn);
|
||||
#ifdef _DURANGO
|
||||
//InputManager.SetEnabledGtcButtons(_360_GTC_MENU|_360_GTC_PAUSE|_360_GTC_VIEW);
|
||||
#endif
|
||||
@@ -136,16 +109,7 @@ 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())
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "UI.h"
|
||||
#include "UIScene_Keyboard.h"
|
||||
#include "..\..\Screen.h"
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
// Global buffer that stores the text entered in the native keyboard scene.
|
||||
@@ -224,6 +225,38 @@ void UIScene_Keyboard::tick()
|
||||
}
|
||||
}
|
||||
|
||||
// Paste from clipboard
|
||||
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
|
||||
{
|
||||
wstring pasted = Screen::getClipboard();
|
||||
wstring sanitized;
|
||||
sanitized.reserve(pasted.length());
|
||||
|
||||
for (wchar_t pc : pasted)
|
||||
{
|
||||
if (pc >= 0x20) // Keep printable characters
|
||||
{
|
||||
if (static_cast<int>(m_win64TextBuffer.length() + sanitized.length()) >= m_win64MaxChars)
|
||||
break;
|
||||
sanitized += pc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sanitized.empty())
|
||||
{
|
||||
if (m_bPCMode)
|
||||
{
|
||||
m_win64TextBuffer.insert(m_iCursorPos, sanitized);
|
||||
m_iCursorPos += (int)sanitized.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_win64TextBuffer += sanitized;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bPCMode)
|
||||
{
|
||||
// Arrow keys, Home, End, Delete for cursor movement
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 50
|
||||
#endif
|
||||
|
||||
int UIScene_LoadMenu::m_iDifficultyTitleSettingA[5]=
|
||||
int UIScene_LoadMenu::m_iDifficultyTitleSettingA[4]=
|
||||
{
|
||||
IDS_DIFFICULTY_TITLE_PEACEFUL,
|
||||
IDS_DIFFICULTY_TITLE_EASY,
|
||||
IDS_DIFFICULTY_TITLE_NORMAL,
|
||||
IDS_DIFFICULTY_TITLE_HARD,
|
||||
IDS_GAMEMODE_HARDCORE
|
||||
IDS_DIFFICULTY_TITLE_HARD
|
||||
};
|
||||
|
||||
int UIScene_LoadMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes)
|
||||
@@ -111,7 +110,6 @@ 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.
|
||||
@@ -259,30 +257,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -572,14 +546,6 @@ 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();
|
||||
@@ -984,15 +950,10 @@ 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;
|
||||
}
|
||||
@@ -1206,7 +1167,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];
|
||||
@@ -1619,24 +1580,6 @@ 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;
|
||||
@@ -1669,7 +1612,6 @@ 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[5];
|
||||
static int m_iDifficultyTitleSettingA[4];
|
||||
|
||||
UIControl m_controlMainPanel;
|
||||
UIControl_Label m_labelGameName, m_labelSeed, m_labelCreatedMode;
|
||||
@@ -71,7 +71,6 @@ 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, bool *outHardcore = nullptr)
|
||||
static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
|
||||
{
|
||||
// Check for a worldname.txt sidecar written by the rename feature first
|
||||
size_t slashPos = filePath.rfind(L'\\');
|
||||
@@ -124,11 +124,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
|
||||
{
|
||||
CompoundTag *dataTag = root->getCompound(L"Data");
|
||||
if (dataTag != nullptr)
|
||||
{
|
||||
result = dataTag->getString(L"LevelName");
|
||||
if (outHardcore)
|
||||
*outHardcore = dataTag->getBoolean(L"hardcore");
|
||||
}
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
@@ -779,9 +775,7 @@ 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");
|
||||
bool saveHardcore = false;
|
||||
wstring levelName = ReadLevelNameFromSaveFile(filePath, &saveHardcore);
|
||||
m_saveDetails[i].isHardcore = saveHardcore;
|
||||
wstring levelName = ReadLevelNameFromSaveFile(filePath);
|
||||
if (!levelName.empty())
|
||||
{
|
||||
m_buttonListSaves.addItem(levelName, wstring(L""));
|
||||
|
||||
@@ -368,7 +368,7 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId)
|
||||
UINT uiIDA[2];
|
||||
uiIDA[0]=IDS_CANCEL;
|
||||
uiIDA[1]=IDS_OK;
|
||||
ui.RequestErrorMessage(IDS_WARNING_ARCADE_TITLE, IDS_WARNING_ARCADE_TEXT, uiIDA, 2, XUSER_INDEX_ANY,&UIScene_MainMenu::ExitGameReturned,this);
|
||||
ui.RequestErrorMessage(IDS_WINDOWS_EXIT, IDS_WARNING_ARCADE_TEXT, uiIDA, 2, XUSER_INDEX_ANY,&UIScene_MainMenu::ExitGameReturned,this);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -247,14 +247,11 @@ 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,7 +11,6 @@
|
||||
#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"
|
||||
@@ -19,7 +18,6 @@
|
||||
#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"
|
||||
@@ -39,26 +37,9 @@ 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);
|
||||
|
||||
@@ -129,16 +110,7 @@ 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;
|
||||
@@ -200,12 +172,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ float GameRenderer::getFov(float a, bool applyEffects)
|
||||
float fov = m_fov;//70;
|
||||
if (applyEffects)
|
||||
{
|
||||
fov += mc->options->fov * 40;
|
||||
//fov += mc->options->fov * 40;
|
||||
fov *= oFov[playerIdx] + (this->fov[playerIdx] - oFov[playerIdx]) * a;
|
||||
}
|
||||
if (player->getHealth() <= 0)
|
||||
|
||||
@@ -854,210 +854,6 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
||||
// font.draw(str, x + 1, y, 0xffffff);
|
||||
// }
|
||||
|
||||
#ifndef _FINAL_BUILD
|
||||
MemSect(31);
|
||||
|
||||
// temporarily render overlay at all times so version is more obvious in bug reports
|
||||
// we can turn this off once things stabilize
|
||||
if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
|
||||
{
|
||||
const int debugLeft = 1;
|
||||
const int debugTop = 1;
|
||||
const float maxContentWidth = 1200.f;
|
||||
const float maxContentHeight = 420.f;
|
||||
float scale = static_cast<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,7 +561,6 @@ MinecraftServer::MinecraftServer()
|
||||
m_serverPausedEvent = new C4JThread::Event;
|
||||
|
||||
m_saveOnExit = false;
|
||||
m_deleteWorldOnExit = false;
|
||||
m_suspending = false;
|
||||
|
||||
m_ugcPlayersVersion = 0;
|
||||
@@ -658,7 +657,7 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
|
||||
setFlightAllowed(GetDedicatedServerBool(settings, L"allow-flight", true));
|
||||
|
||||
// 4J Stu - Enabling flight to stop it kicking us when we use it
|
||||
#ifdef _DEBUG_MENUS_ENABLED
|
||||
#if (defined _DEBUG_MENUS_ENABLED && defined _DEBUG)
|
||||
setFlightAllowed(true);
|
||||
#endif
|
||||
|
||||
@@ -888,15 +887,6 @@ 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);
|
||||
|
||||
@@ -1652,7 +1642,7 @@ bool MinecraftServer::isNetherEnabled()
|
||||
|
||||
bool MinecraftServer::isHardcore()
|
||||
{
|
||||
return app.GetGameHostOption(eGameHostOption_Hardcore) > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int MinecraftServer::getOperatorUserPermissionLevel()
|
||||
@@ -1725,330 +1715,345 @@ void MinecraftServer::setPlayerIdleTimeout(int playerIdleTimeout)
|
||||
extern int c0a, c0b, c1a, c1b, c1c, c2a, c2b;
|
||||
void MinecraftServer::run(int64_t seed, void *lpParameter)
|
||||
{
|
||||
NetworkGameInitData *initData = nullptr;
|
||||
DWORD initSettings = 0;
|
||||
bool findSeed = false;
|
||||
NetworkGameInitData *initData = nullptr;
|
||||
DWORD initSettings = 0;
|
||||
bool findSeed = false;
|
||||
if(lpParameter != nullptr)
|
||||
{
|
||||
initData = static_cast<NetworkGameInitData *>(lpParameter);
|
||||
initSettings = app.GetGameHostOption(eGameHostOption_All);
|
||||
findSeed = initData->findSeed;
|
||||
m_texturePackId = initData->texturePackId;
|
||||
}
|
||||
// try { // 4J - removed try/catch/finally
|
||||
bool didInit = false;
|
||||
{
|
||||
initData = static_cast<NetworkGameInitData *>(lpParameter);
|
||||
initSettings = app.GetGameHostOption(eGameHostOption_All);
|
||||
findSeed = initData->findSeed;
|
||||
m_texturePackId = initData->texturePackId;
|
||||
}
|
||||
// try { // 4J - removed try/catch/finally
|
||||
bool didInit = false;
|
||||
if (initServer(seed, initData, initSettings,findSeed))
|
||||
{
|
||||
didInit = true;
|
||||
ServerLevel *levelNormalDimension = levels[0];
|
||||
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
{
|
||||
didInit = true;
|
||||
ServerLevel *levelNormalDimension = levels[0];
|
||||
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
LevelData *pLevelData=levelNormalDimension->getLevelData();
|
||||
|
||||
if(pLevelData && pLevelData->getHasStronghold()==false)
|
||||
{
|
||||
{
|
||||
int x,z;
|
||||
if(app.GetTerrainFeaturePosition(eTerrainFeature_Stronghold,&x,&z))
|
||||
{
|
||||
pLevelData->setXStronghold(x);
|
||||
pLevelData->setZStronghold(z);
|
||||
pLevelData->setHasStronghold();
|
||||
}
|
||||
}
|
||||
{
|
||||
pLevelData->setXStronghold(x);
|
||||
pLevelData->setZStronghold(z);
|
||||
pLevelData->setHasStronghold();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t lastTime = getCurrentTimeMillis();
|
||||
int64_t unprocessedTime = 0;
|
||||
while (running && !s_bServerHalted)
|
||||
{
|
||||
int64_t now = getCurrentTimeMillis();
|
||||
int64_t lastTime = getCurrentTimeMillis();
|
||||
int64_t unprocessedTime = 0;
|
||||
while (running && !s_bServerHalted)
|
||||
{
|
||||
int64_t now = getCurrentTimeMillis();
|
||||
|
||||
// 4J Stu - When we pause the server, we don't want to count that as time passed
|
||||
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
|
||||
// 4J Stu - When we pause the server, we don't want to count that as time passed
|
||||
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
|
||||
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
|
||||
//if(m_isServerPaused) lastTime = now;
|
||||
|
||||
int64_t passedTime = now - lastTime;
|
||||
if (passedTime > MS_PER_TICK * 40)
|
||||
{
|
||||
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
|
||||
passedTime = MS_PER_TICK * 40;
|
||||
}
|
||||
if (passedTime < 0)
|
||||
{
|
||||
// logger.warning("Time ran backwards! Did the system time change?");
|
||||
passedTime = 0;
|
||||
}
|
||||
unprocessedTime += passedTime;
|
||||
lastTime = now;
|
||||
int64_t passedTime = now - lastTime;
|
||||
if (passedTime > MS_PER_TICK * 40)
|
||||
{
|
||||
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
|
||||
passedTime = MS_PER_TICK * 40;
|
||||
}
|
||||
if (passedTime < 0)
|
||||
{
|
||||
// logger.warning("Time ran backwards! Did the system time change?");
|
||||
passedTime = 0;
|
||||
}
|
||||
unprocessedTime += passedTime;
|
||||
lastTime = now;
|
||||
|
||||
// 4J Added ability to pause the server
|
||||
// 4J Added ability to pause the server
|
||||
if( !m_isServerPaused )
|
||||
{
|
||||
bool didTick = false;
|
||||
if (levels[0]->allPlayersAreSleeping())
|
||||
{
|
||||
tick();
|
||||
unprocessedTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// int tickcount = 0;
|
||||
// int64_t beforeall = System::currentTimeMillis();
|
||||
while (unprocessedTime > MS_PER_TICK)
|
||||
{
|
||||
unprocessedTime -= MS_PER_TICK;
|
||||
chunkPacketManagement_PreTick();
|
||||
// int64_t before = System::currentTimeMillis();
|
||||
tick();
|
||||
// int64_t after = System::currentTimeMillis();
|
||||
// PIXReportCounter(L"Server time",(float)(after-before));
|
||||
{
|
||||
bool didTick = false;
|
||||
if (levels[0]->allPlayersAreSleeping())
|
||||
{
|
||||
tick();
|
||||
unprocessedTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// int tickcount = 0;
|
||||
// int64_t beforeall = System::currentTimeMillis();
|
||||
while (unprocessedTime > MS_PER_TICK)
|
||||
{
|
||||
unprocessedTime -= MS_PER_TICK;
|
||||
chunkPacketManagement_PreTick();
|
||||
// int64_t before = System::currentTimeMillis();
|
||||
tick();
|
||||
// int64_t after = System::currentTimeMillis();
|
||||
// PIXReportCounter(L"Server time",(float)(after-before));
|
||||
|
||||
chunkPacketManagement_PostTick();
|
||||
}
|
||||
// int64_t afterall = System::currentTimeMillis();
|
||||
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
|
||||
// PIXReportCounter(L"Server ticks",(float)tickcount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4J Stu - TU1-hotfix
|
||||
chunkPacketManagement_PostTick();
|
||||
}
|
||||
// int64_t afterall = System::currentTimeMillis();
|
||||
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
|
||||
// PIXReportCounter(L"Server ticks",(float)tickcount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4J Stu - TU1-hotfix
|
||||
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
|
||||
// The connections should tick at the same frequency even when paused
|
||||
while (unprocessedTime > MS_PER_TICK)
|
||||
{
|
||||
unprocessedTime -= MS_PER_TICK;
|
||||
// Keep ticking the connections to stop them timing out
|
||||
connection->tick();
|
||||
}
|
||||
}
|
||||
// The connections should tick at the same frequency even when paused
|
||||
while (unprocessedTime > MS_PER_TICK)
|
||||
{
|
||||
unprocessedTime -= MS_PER_TICK;
|
||||
// Keep ticking the connections to stop them timing out
|
||||
connection->tick();
|
||||
}
|
||||
}
|
||||
if(MinecraftServer::setTimeAtEndOfTick)
|
||||
{
|
||||
MinecraftServer::setTimeAtEndOfTick = false;
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
{
|
||||
MinecraftServer::setTimeAtEndOfTick = false;
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
level->setGameTime( MinecraftServer::setTime );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(MinecraftServer::setTimeOfDayAtEndOfTick)
|
||||
{
|
||||
MinecraftServer::setTimeOfDayAtEndOfTick = false;
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
{
|
||||
MinecraftServer::setTimeOfDayAtEndOfTick = false;
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
level->setDayTime( MinecraftServer::setTimeOfDay );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process delayed actions
|
||||
eXuiServerAction eAction;
|
||||
LPVOID param;
|
||||
// Process delayed actions
|
||||
eXuiServerAction eAction;
|
||||
LPVOID param;
|
||||
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
||||
{
|
||||
eAction = app.GetXuiServerAction(i);
|
||||
param = app.GetXuiServerActionParam(i);
|
||||
{
|
||||
eAction = app.GetXuiServerAction(i);
|
||||
param = app.GetXuiServerActionParam(i);
|
||||
|
||||
switch(eAction)
|
||||
{
|
||||
case eXuiServerAction_AutoSaveGame:
|
||||
{
|
||||
case eXuiServerAction_AutoSaveGame:
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(MINECRAFT_SERVER_BUILD)
|
||||
{
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
{
|
||||
PIXBeginNamedEvent(0,"Autosave");
|
||||
PIXBeginNamedEvent(0, "Autosave");
|
||||
|
||||
// Get the frequency of the timer
|
||||
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
|
||||
float fElapsedTime = 0.0f;
|
||||
QueryPerformanceFrequency( &qwTicksPerSec );
|
||||
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
|
||||
// Get the frequency of the timer
|
||||
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
|
||||
float fElapsedTime = 0.0f;
|
||||
QueryPerformanceFrequency(&qwTicksPerSec);
|
||||
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
|
||||
|
||||
// Save the start time
|
||||
QueryPerformanceCounter( &qwTime );
|
||||
|
||||
if (players != nullptr)
|
||||
{
|
||||
players->saveAll(nullptr);
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < levels.length; j++)
|
||||
{
|
||||
if( s_bServerHalted ) break;
|
||||
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
|
||||
// with the data from the nethers leveldata.
|
||||
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
|
||||
ServerLevel *level = levels[levels.length - 1 - j];
|
||||
PIXBeginNamedEvent(0, "Saving level %d",levels.length - 1 - j);
|
||||
level->save(false, nullptr, true);
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
if( !s_bServerHalted )
|
||||
{
|
||||
PIXBeginNamedEvent(0,"Saving game rules");
|
||||
saveGameRules();
|
||||
PIXEndNamedEvent();
|
||||
|
||||
PIXBeginNamedEvent(0,"Save to disc");
|
||||
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
|
||||
PIXEndNamedEvent();
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
|
||||
QueryPerformanceCounter( &qwNewTime );
|
||||
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
|
||||
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
|
||||
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
|
||||
}
|
||||
break;
|
||||
// Save the start time
|
||||
QueryPerformanceCounter(&qwTime);
|
||||
#endif
|
||||
case eXuiServerAction_SaveGame:
|
||||
app.EnterSaveNotificationSection();
|
||||
if (players != nullptr)
|
||||
{
|
||||
players->saveAll(Minecraft::GetInstance()->progressRenderer);
|
||||
}
|
||||
|
||||
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
|
||||
if (players != nullptr)
|
||||
{
|
||||
players->saveAll(nullptr);
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < levels.length; j++)
|
||||
{
|
||||
for (unsigned int j = 0; j < levels.length; j++)
|
||||
{
|
||||
if( s_bServerHalted ) break;
|
||||
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
|
||||
// with the data from the nethers leveldata.
|
||||
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
|
||||
ServerLevel *level = levels[levels.length - 1 - j];
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXBeginNamedEvent(0, "Saving level %d", levels.length - 1 - j);
|
||||
#endif
|
||||
level->save(false, nullptr, true);
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXEndNamedEvent();
|
||||
#endif
|
||||
}
|
||||
if (!s_bServerHalted)
|
||||
{
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXBeginNamedEvent(0, "Saving game rules");
|
||||
#endif
|
||||
saveGameRules();
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXEndNamedEvent();
|
||||
|
||||
PIXBeginNamedEvent(0, "Save to disc");
|
||||
#endif
|
||||
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXEndNamedEvent();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_XBOX_ONE) || defined(__ORBIS__)
|
||||
PIXEndNamedEvent();
|
||||
|
||||
QueryPerformanceCounter(&qwNewTime);
|
||||
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
|
||||
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
|
||||
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case eXuiServerAction_SaveGame:
|
||||
app.EnterSaveNotificationSection();
|
||||
if (players != nullptr)
|
||||
{
|
||||
players->saveAll(Minecraft::GetInstance()->progressRenderer);
|
||||
}
|
||||
|
||||
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
|
||||
|
||||
for (unsigned int j = 0; j < levels.length; j++)
|
||||
{
|
||||
if( s_bServerHalted ) break;
|
||||
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
|
||||
// with the data from the nethers leveldata.
|
||||
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
|
||||
ServerLevel *level = levels[levels.length - 1 - j];
|
||||
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
|
||||
// with the data from the nethers leveldata.
|
||||
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
|
||||
ServerLevel *level = levels[levels.length - 1 - j];
|
||||
level->save(true, Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
|
||||
|
||||
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
|
||||
}
|
||||
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
|
||||
}
|
||||
if( !s_bServerHalted )
|
||||
{
|
||||
saveGameRules();
|
||||
{
|
||||
saveGameRules();
|
||||
|
||||
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
|
||||
}
|
||||
app.LeaveSaveNotificationSection();
|
||||
break;
|
||||
case eXuiServerAction_DropItem:
|
||||
// Find the player, and drop the id at their feet
|
||||
{
|
||||
shared_ptr<ServerPlayer> player = players->players.at(0);
|
||||
}
|
||||
app.LeaveSaveNotificationSection();
|
||||
break;
|
||||
case eXuiServerAction_DropItem:
|
||||
// Find the player, and drop the id at their feet
|
||||
{
|
||||
shared_ptr<ServerPlayer> player = players->players.at(0);
|
||||
size_t id = (size_t) param;
|
||||
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_SpawnMob:
|
||||
{
|
||||
shared_ptr<ServerPlayer> player = players->players.at(0);
|
||||
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
|
||||
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_SpawnMob:
|
||||
{
|
||||
shared_ptr<ServerPlayer> player = players->players.at(0);
|
||||
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
|
||||
shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(EntityIO::newByEnumType(factory,player->level ));
|
||||
mob->moveTo(player->x+1, player->y, player->z+1, player->level->random->nextFloat() * 360, 0);
|
||||
mob->setDespawnProtected(); // 4J added, default to being protected against despawning (has to be done after initial position is set)
|
||||
player->level->addEntity(mob);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_PauseServer:
|
||||
player->level->addEntity(mob);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_PauseServer:
|
||||
m_isServerPaused = ( (size_t) param == TRUE );
|
||||
if( m_isServerPaused )
|
||||
{
|
||||
m_serverPausedEvent->Set();
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ToggleRain:
|
||||
{
|
||||
bool isRaining = levels[0]->getLevelData()->isRaining();
|
||||
levels[0]->getLevelData()->setRaining(!isRaining);
|
||||
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ToggleThunder:
|
||||
{
|
||||
bool isThundering = levels[0]->getLevelData()->isThundering();
|
||||
levels[0]->getLevelData()->setThundering(!isThundering);
|
||||
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ServerSettingChanged_Gamertags:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
|
||||
break;
|
||||
case eXuiServerAction_ServerSettingChanged_BedrockFog:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
|
||||
break;
|
||||
{
|
||||
m_serverPausedEvent->Set();
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ToggleRain:
|
||||
{
|
||||
bool isRaining = levels[0]->getLevelData()->isRaining();
|
||||
levels[0]->getLevelData()->setRaining(!isRaining);
|
||||
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ToggleThunder:
|
||||
{
|
||||
bool isThundering = levels[0]->getLevelData()->isThundering();
|
||||
levels[0]->getLevelData()->setThundering(!isThundering);
|
||||
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
|
||||
}
|
||||
break;
|
||||
case eXuiServerAction_ServerSettingChanged_Gamertags:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
|
||||
break;
|
||||
case eXuiServerAction_ServerSettingChanged_BedrockFog:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
|
||||
break;
|
||||
|
||||
case eXuiServerAction_ServerSettingChanged_Difficulty:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
|
||||
break;
|
||||
case eXuiServerAction_ExportSchematic:
|
||||
case eXuiServerAction_ServerSettingChanged_Difficulty:
|
||||
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
|
||||
break;
|
||||
case eXuiServerAction_ExportSchematic:
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
app.EnterSaveNotificationSection();
|
||||
app.EnterSaveNotificationSection();
|
||||
|
||||
//players->broadcastAll( shared_ptr<UpdateProgressPacket>( new UpdateProgressPacket(20) ) );
|
||||
|
||||
if( !s_bServerHalted )
|
||||
{
|
||||
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
|
||||
{
|
||||
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
|
||||
#ifdef _XBOX
|
||||
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
|
||||
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
|
||||
#else
|
||||
File targetFileDir(L"Schematics");
|
||||
File targetFileDir(L"Schematics");
|
||||
#endif
|
||||
if(!targetFileDir.exists()) targetFileDir.mkdir();
|
||||
|
||||
wchar_t filename[128];
|
||||
wchar_t filename[128];
|
||||
swprintf(filename,128,L"%ls%dx%dx%d.sch",initData->name,(initData->endX - initData->startX + 1), (initData->endY - initData->startY + 1), (initData->endZ - initData->startZ + 1));
|
||||
|
||||
File dataFile = File( targetFileDir, wstring(filename) );
|
||||
if(dataFile.exists()) dataFile._delete();
|
||||
FileOutputStream fos = FileOutputStream(dataFile);
|
||||
DataOutputStream dos = DataOutputStream(&fos);
|
||||
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
|
||||
dos.close();
|
||||
FileOutputStream fos = FileOutputStream(dataFile);
|
||||
DataOutputStream dos = DataOutputStream(&fos);
|
||||
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
|
||||
dos.close();
|
||||
|
||||
delete initData;
|
||||
}
|
||||
app.LeaveSaveNotificationSection();
|
||||
delete initData;
|
||||
}
|
||||
app.LeaveSaveNotificationSection();
|
||||
#endif
|
||||
break;
|
||||
case eXuiServerAction_SetCameraLocation:
|
||||
break;
|
||||
case eXuiServerAction_SetCameraLocation:
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
{
|
||||
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
|
||||
{
|
||||
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
|
||||
|
||||
app.DebugPrintf( "DEBUG: Player=%i\n", pos->player );
|
||||
app.DebugPrintf( "DEBUG: Teleporting to pos=(%f.2, %f.2, %f.2), looking at=(%f.2,%f.2)\n",
|
||||
pos->m_camX, pos->m_camY, pos->m_camZ,
|
||||
pos->m_camX, pos->m_camY, pos->m_camZ,
|
||||
pos->m_yRot, pos->m_elev
|
||||
);
|
||||
|
||||
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
|
||||
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
|
||||
player->debug_setPosition( pos->m_camX, pos->m_camY, pos->m_camZ,
|
||||
pos->m_yRot, pos->m_elev );
|
||||
|
||||
// Doesn't work
|
||||
// Doesn't work
|
||||
//player->setYHeadRot(pos->m_yRot);
|
||||
//player->absMoveTo(pos->m_camX, pos->m_camY, pos->m_camZ, pos->m_yRot, pos->m_elev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
app.SetXuiServerAction(i,eXuiServerAction_Idle);
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
//else
|
||||
//{
|
||||
//{
|
||||
// while (running)
|
||||
// {
|
||||
// {
|
||||
// handleConsoleInputs();
|
||||
// Sleep(10);
|
||||
// Sleep(10);
|
||||
// }
|
||||
//}
|
||||
#if 0
|
||||
@@ -2075,9 +2080,9 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
|
||||
}
|
||||
#endif
|
||||
|
||||
// 4J Stu - Stop the server when the loops complete, as the finally would do
|
||||
stopServer(didInit);
|
||||
stopped = true;
|
||||
// 4J Stu - Stop the server when the loops complete, as the finally would do
|
||||
stopServer(didInit);
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
void MinecraftServer::broadcastStartSavingPacket()
|
||||
@@ -2385,6 +2390,9 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
|
||||
{
|
||||
if( player == nullptr ) return false;
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
return true;
|
||||
#else
|
||||
int time = GetTickCount();
|
||||
DWORD currentPlayerCount = g_NetworkManager.GetPlayerCount();
|
||||
if( currentPlayerCount == 0 ) return false;
|
||||
@@ -2396,6 +2404,7 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MinecraftServer::chunkPacketManagement_DidSendTo(INetworkPlayer *player)
|
||||
|
||||
@@ -265,8 +265,6 @@ 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:
|
||||
@@ -280,9 +278,6 @@ 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,7 +1,6 @@
|
||||
#include "ConsoleInputSource.h"
|
||||
#include "..\Minecraft.World\PacketListener.h"
|
||||
#include "..\Minecraft.World\JavaIntHash.h"
|
||||
#include <atomic>
|
||||
|
||||
class MinecraftServer;
|
||||
class Connection;
|
||||
@@ -131,8 +130,8 @@ public:
|
||||
|
||||
void setShowOnMaps(bool bVal);
|
||||
|
||||
void setWasKicked() { m_bWasKicked.store(true); }
|
||||
bool getWasKicked() { return m_bWasKicked.load(); }
|
||||
void setWasKicked() { m_bWasKicked = true; }
|
||||
bool getWasKicked() { return m_bWasKicked; }
|
||||
|
||||
// 4J Added
|
||||
bool hasClientTickedOnce() { return m_bHasClientTickedOnce; }
|
||||
@@ -141,5 +140,5 @@ private:
|
||||
bool m_bCloseOnTick;
|
||||
vector<wstring> m_texturesRequested;
|
||||
|
||||
std::atomic<bool> m_bWasKicked{false};
|
||||
bool m_bWasKicked;
|
||||
};
|
||||
@@ -67,7 +67,6 @@ 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);
|
||||
}
|
||||
@@ -81,7 +80,6 @@ PlayerList::~PlayerList()
|
||||
player->gameMode = nullptr;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&m_banCS);
|
||||
DeleteCriticalSection(&m_kickPlayersCS);
|
||||
DeleteCriticalSection(&m_closePlayersCS);
|
||||
}
|
||||
@@ -273,8 +271,7 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
|
||||
static_cast<BYTE>(playerIndex), level->useNewSeaLevel(),
|
||||
player->getAllPlayerGamePrivileges(),
|
||||
level->getLevelData()->getXZSize(),
|
||||
level->getLevelData()->getHellScale(),
|
||||
level->getLevelData()->isHardcore()));
|
||||
level->getLevelData()->getHellScale()));
|
||||
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));
|
||||
@@ -705,13 +702,6 @@ 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
|
||||
@@ -749,7 +739,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(), level->getLevelData()->isHardcore() ) );
|
||||
player->level->useNewSeaLevel(), player->entityId, level->getLevelData()->getXZSize(), level->getLevelData()->getHellScale() ) );
|
||||
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) );
|
||||
|
||||
@@ -866,7 +856,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->getLevelData()->isHardcore()));
|
||||
newLevel->useNewSeaLevel(), player->entityId, newLevel->getLevelData()->getXZSize(), newLevel->getLevelData()->getHellScale()));
|
||||
|
||||
oldLevel->removeEntityImmediately(player);
|
||||
player->removed = false;
|
||||
@@ -1680,7 +1670,6 @@ bool PlayerList::isXuidBanned(PlayerUID xuid)
|
||||
|
||||
bool banned = false;
|
||||
|
||||
EnterCriticalSection(&m_banCS);
|
||||
for(PlayerUID it : m_bannedXuids)
|
||||
{
|
||||
if( ProfileManager.AreXUIDSEqual( xuid, it ) )
|
||||
@@ -1689,7 +1678,6 @@ bool PlayerList::isXuidBanned(PlayerUID xuid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&m_banCS);
|
||||
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
if (!banned && g_Win64DedicatedServer)
|
||||
@@ -1701,34 +1689,6 @@ 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,7 +31,6 @@ 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;
|
||||
@@ -136,7 +135,6 @@ 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);
|
||||
};
|
||||
|
||||
@@ -204,7 +204,7 @@ void Screen::updateEvents()
|
||||
// Map to Screen::keyPressed
|
||||
int mappedKey = -1;
|
||||
wchar_t ch = 0;
|
||||
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
|
||||
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
|
||||
else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
|
||||
else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
|
||||
else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
|
||||
|
||||
@@ -303,12 +303,6 @@ 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);
|
||||
|
||||
@@ -146,7 +146,8 @@ void ServerPlayer::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFou
|
||||
if( ( *removedFound ) == false )
|
||||
{
|
||||
*removedFound = true;
|
||||
memset(flags, 0, 2048/32);
|
||||
// before this left 192 bytes uninitialized!!!!!
|
||||
memset(flags, 0, (2048 / 32) * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
for(int index : entitiesToRemove)
|
||||
@@ -376,6 +377,9 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
|
||||
// connection->done);
|
||||
// }
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
if (dontDelayChunks || (canSendToPlayer && !connection->done))
|
||||
#else
|
||||
if( dontDelayChunks ||
|
||||
(canSendToPlayer &&
|
||||
#ifdef _XBOX_ONE
|
||||
@@ -390,21 +394,22 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
|
||||
#endif
|
||||
//(tickCount - lastBrupSendTickCount) > (connection->getNetworkPlayer()->GetCurrentRtt()>>4) &&
|
||||
!connection->done) )
|
||||
{
|
||||
lastBrupSendTickCount = tickCount;
|
||||
okToSend = true;
|
||||
MinecraftServer::chunkPacketManagement_DidSendTo(connection->getNetworkPlayer());
|
||||
#endif
|
||||
{
|
||||
lastBrupSendTickCount = tickCount;
|
||||
okToSend = true;
|
||||
MinecraftServer::chunkPacketManagement_DidSendTo(connection->getNetworkPlayer());
|
||||
|
||||
// static unordered_map<wstring,int64_t> mapLastTime;
|
||||
// int64_t thisTime = System::currentTimeMillis();
|
||||
// int64_t lastTime = mapLastTime[connection->getNetworkPlayer()->GetUID().toString()];
|
||||
// app.DebugPrintf(" - OK to send (%d ms since last)\n", thisTime - lastTime);
|
||||
// mapLastTime[connection->getNetworkPlayer()->GetUID().toString()] = thisTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// app.DebugPrintf(" - <NOT OK>\n");
|
||||
}
|
||||
// static unordered_map<wstring,int64_t> mapLastTime;
|
||||
// int64_t thisTime = System::currentTimeMillis();
|
||||
// int64_t lastTime = mapLastTime[connection->getNetworkPlayer()->GetUID().toString()];
|
||||
// app.DebugPrintf(" - OK to send (%d ms since last)\n", thisTime - lastTime);
|
||||
// mapLastTime[connection->getNetworkPlayer()->GetUID().toString()] = thisTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// app.DebugPrintf(" - <NOT OK>\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (okToSend)
|
||||
@@ -564,17 +569,6 @@ 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();
|
||||
@@ -1615,9 +1609,9 @@ bool ServerPlayer::hasPermission(EGameCommand command)
|
||||
//
|
||||
// // 4J - Don't need
|
||||
// //if (server.isSingleplayer() && server.getSingleplayerName().equals(name))
|
||||
/// //{
|
||||
// //{
|
||||
// // server.setDifficulty(packet.getDifficulty());
|
||||
/// //}
|
||||
// //}
|
||||
//}
|
||||
|
||||
int ServerPlayer::getViewDistance()
|
||||
|
||||
@@ -25,12 +25,20 @@ public:
|
||||
static const int KEY_DROP = 'Q';
|
||||
static const int KEY_CRAFTING = 'C';
|
||||
static const int KEY_CRAFTING_ALT = 'R';
|
||||
static const int KEY_CHAT = 'T';
|
||||
static const int KEY_CONFIRM = VK_RETURN;
|
||||
static const int KEY_CANCEL = VK_ESCAPE;
|
||||
static const int KEY_PAUSE = VK_ESCAPE;
|
||||
static const int KEY_THIRD_PERSON = VK_F5;
|
||||
static const int KEY_TOGGLE_HUD = VK_F1;
|
||||
static const int KEY_DEBUG_INFO = VK_F3;
|
||||
static const int KEY_DEBUG_MENU = VK_F4;
|
||||
static const int KEY_THIRD_PERSON = VK_F5;
|
||||
static const int KEY_DEBUG_CONSOLE = VK_F6;
|
||||
static const int KEY_HOST_SETTINGS = VK_F8;
|
||||
static const int KEY_FULLSCREEN = VK_F11;
|
||||
|
||||
// todo: implement and shi
|
||||
static const int KEY_SCREENSHOT = VK_F2;
|
||||
|
||||
void Init();
|
||||
void Tick();
|
||||
|
||||
@@ -121,7 +121,6 @@ static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
|
||||
struct Win64LaunchOptions
|
||||
{
|
||||
int screenMode;
|
||||
bool serverMode;
|
||||
bool fullscreen;
|
||||
};
|
||||
|
||||
@@ -207,13 +206,9 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
{
|
||||
Win64LaunchOptions options = {};
|
||||
options.screenMode = 0;
|
||||
options.serverMode = false;
|
||||
|
||||
g_Win64MultiplayerJoin = false;
|
||||
g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
|
||||
g_Win64DedicatedServer = false;
|
||||
g_Win64DedicatedServerPort = WIN64_NET_DEFAULT_PORT;
|
||||
g_Win64DedicatedServerBindIP[0] = 0;
|
||||
|
||||
int argc = 0;
|
||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
@@ -226,17 +221,6 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
options.screenMode = argv[1][0] - L'0';
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (_wcsicmp(argv[i], L"-server") == 0)
|
||||
{
|
||||
options.serverMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_Win64DedicatedServer = options.serverMode;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (_wcsicmp(argv[i], L"-name") == 0 && (i + 1) < argc)
|
||||
@@ -247,15 +231,8 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
{
|
||||
char ipBuf[256];
|
||||
CopyWideArgToAnsi(argv[++i], ipBuf, sizeof(ipBuf));
|
||||
if (options.serverMode)
|
||||
{
|
||||
strncpy_s(g_Win64DedicatedServerBindIP, sizeof(g_Win64DedicatedServerBindIP), ipBuf, _TRUNCATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
|
||||
g_Win64MultiplayerJoin = true;
|
||||
}
|
||||
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
|
||||
g_Win64MultiplayerJoin = true;
|
||||
}
|
||||
else if (_wcsicmp(argv[i], L"-port") == 0 && (i + 1) < argc)
|
||||
{
|
||||
@@ -263,10 +240,7 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
const long port = wcstol(argv[++i], &endPtr, 10);
|
||||
if (endPtr != argv[i] && *endPtr == 0 && port > 0 && port <= 65535)
|
||||
{
|
||||
if (options.serverMode)
|
||||
g_Win64DedicatedServerPort = static_cast<int>(port);
|
||||
else
|
||||
g_Win64MultiplayerPort = static_cast<int>(port);
|
||||
g_Win64MultiplayerPort = static_cast<int>(port);
|
||||
}
|
||||
}
|
||||
else if (_wcsicmp(argv[i], L"-fullscreen") == 0)
|
||||
@@ -277,36 +251,6 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
return options;
|
||||
}
|
||||
|
||||
static BOOL WINAPI HeadlessServerCtrlHandler(DWORD ctrlType)
|
||||
{
|
||||
switch (ctrlType)
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
app.m_bShutdown = true;
|
||||
MinecraftServer::HaltServer();
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupHeadlessServerConsole()
|
||||
{
|
||||
if (AllocConsole())
|
||||
{
|
||||
FILE* stream = nullptr;
|
||||
freopen_s(&stream, "CONIN$", "r", stdin);
|
||||
freopen_s(&stream, "CONOUT$", "w", stdout);
|
||||
freopen_s(&stream, "CONOUT$", "w", stderr);
|
||||
SetConsoleTitleA("Minecraft Server");
|
||||
}
|
||||
|
||||
SetConsoleCtrlHandler(HeadlessServerCtrlHandler, TRUE);
|
||||
}
|
||||
|
||||
void DefineActions(void)
|
||||
{
|
||||
// The app needs to define the actions required, and the possible mappings for these
|
||||
@@ -1350,161 +1294,6 @@ static Minecraft* InitialiseMinecraftRuntime()
|
||||
return pMinecraft;
|
||||
}
|
||||
|
||||
static int HeadlessServerConsoleThreadProc(void* lpParameter)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpParameter);
|
||||
|
||||
std::string line;
|
||||
while (!app.m_bShutdown)
|
||||
{
|
||||
if (!std::getline(std::cin, line))
|
||||
{
|
||||
if (std::cin.eof())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::cin.clear();
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
wstring command = trimString(convStringToWstring(line));
|
||||
if (command.empty())
|
||||
continue;
|
||||
|
||||
MinecraftServer* server = MinecraftServer::getInstance();
|
||||
if (server != nullptr)
|
||||
{
|
||||
server->handleConsoleInput(command, server);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RunHeadlessServer()
|
||||
{
|
||||
SetupHeadlessServerConsole();
|
||||
|
||||
Settings serverSettings(new File(L"server.properties"));
|
||||
const wstring configuredBindIp = serverSettings.getString(L"server-ip", L"");
|
||||
|
||||
const char* bindIp = "*";
|
||||
if (g_Win64DedicatedServerBindIP[0] != 0)
|
||||
{
|
||||
bindIp = g_Win64DedicatedServerBindIP;
|
||||
}
|
||||
else if (!configuredBindIp.empty())
|
||||
{
|
||||
bindIp = wstringtochararray(configuredBindIp);
|
||||
}
|
||||
|
||||
const int port = g_Win64DedicatedServerPort > 0 ? g_Win64DedicatedServerPort : serverSettings.getInt(L"server-port", WIN64_NET_DEFAULT_PORT);
|
||||
|
||||
printf("Starting headless server on %s:%d\n", bindIp, port);
|
||||
fflush(stdout);
|
||||
|
||||
const Minecraft* pMinecraft = InitialiseMinecraftRuntime();
|
||||
if (pMinecraft == nullptr)
|
||||
{
|
||||
fprintf(stderr, "Failed to initialise the Minecraft runtime.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
app.SetGameHostOption(eGameHostOption_Difficulty, serverSettings.getInt(L"difficulty", 1));
|
||||
app.SetGameHostOption(eGameHostOption_Gamertags, 1);
|
||||
app.SetGameHostOption(eGameHostOption_GameType, serverSettings.getInt(L"gamemode", 0));
|
||||
app.SetGameHostOption(eGameHostOption_LevelType, 0);
|
||||
app.SetGameHostOption(eGameHostOption_Structures, serverSettings.getBoolean(L"generate-structures", true) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_BonusChest, serverSettings.getBoolean(L"bonus-chest", false) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_PvP, serverSettings.getBoolean(L"pvp", true) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_TrustPlayers, serverSettings.getBoolean(L"trust-players", true) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_FireSpreads, serverSettings.getBoolean(L"fire-spreads", true) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_TNT, serverSettings.getBoolean(L"tnt", true) ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_HostCanFly, 1);
|
||||
app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, 1);
|
||||
app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, 1);
|
||||
app.SetGameHostOption(eGameHostOption_MobGriefing, 1);
|
||||
app.SetGameHostOption(eGameHostOption_KeepInventory, 0);
|
||||
app.SetGameHostOption(eGameHostOption_DoMobSpawning, 1);
|
||||
app.SetGameHostOption(eGameHostOption_DoMobLoot, 1);
|
||||
app.SetGameHostOption(eGameHostOption_DoTileDrops, 1);
|
||||
app.SetGameHostOption(eGameHostOption_NaturalRegeneration, 1);
|
||||
app.SetGameHostOption(eGameHostOption_DoDaylightCycle, 1);
|
||||
|
||||
MinecraftServer::resetFlags();
|
||||
g_NetworkManager.HostGame(0, false, true, MINECRAFT_NET_MAX_PLAYERS, 0);
|
||||
|
||||
if (!WinsockNetLayer::IsActive())
|
||||
{
|
||||
fprintf(stderr, "Failed to bind the server socket on %s:%d.\n", bindIp, port);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_NetworkManager.FakeLocalPlayerJoined();
|
||||
|
||||
NetworkGameInitData* param = new NetworkGameInitData();
|
||||
param->seed = 0;
|
||||
param->settings = app.GetGameHostOption(eGameHostOption_All);
|
||||
|
||||
g_NetworkManager.ServerStoppedCreate(true);
|
||||
g_NetworkManager.ServerReadyCreate(true);
|
||||
|
||||
C4JThread* thread = new C4JThread(&CGameNetworkManager::ServerThreadProc, param, "Server", 256 * 1024);
|
||||
thread->SetProcessor(CPU_CORE_SERVER);
|
||||
thread->Run();
|
||||
|
||||
g_NetworkManager.ServerReadyWait();
|
||||
g_NetworkManager.ServerReadyDestroy();
|
||||
|
||||
if (MinecraftServer::serverHalted())
|
||||
{
|
||||
fprintf(stderr, "The server halted during startup.\n");
|
||||
g_NetworkManager.LeaveGame(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
app.SetGameStarted(true);
|
||||
g_NetworkManager.DoWork();
|
||||
|
||||
printf("Server ready on %s:%d\n", bindIp, port);
|
||||
printf("Type 'help' for server commands.\n");
|
||||
fflush(stdout);
|
||||
|
||||
C4JThread* consoleThread = new C4JThread(&HeadlessServerConsoleThreadProc, nullptr, "Server console", 128 * 1024);
|
||||
consoleThread->Run();
|
||||
|
||||
MSG msg = { 0 };
|
||||
while (WM_QUIT != msg.message && !app.m_bShutdown && !MinecraftServer::serverHalted())
|
||||
{
|
||||
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
app.UpdateTime();
|
||||
ProfileManager.Tick();
|
||||
StorageManager.Tick();
|
||||
RenderManager.Tick();
|
||||
ui.tick();
|
||||
g_NetworkManager.DoWork();
|
||||
app.HandleXuiActions();
|
||||
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
printf("Stopping server...\n");
|
||||
fflush(stdout);
|
||||
|
||||
app.m_bShutdown = true;
|
||||
MinecraftServer::HaltServer();
|
||||
g_NetworkManager.LeaveGame(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
_In_opt_ HINSTANCE hPrevInstance,
|
||||
_In_ LPTSTR lpCmdLine,
|
||||
@@ -1566,11 +1355,8 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
const Win64LaunchOptions launchOptions = ParseLaunchOptions();
|
||||
ApplyScreenMode(launchOptions.screenMode);
|
||||
|
||||
// Ensure uid.dat exists from startup in client mode (before any multiplayer/login path).
|
||||
if (!launchOptions.serverMode)
|
||||
{
|
||||
Win64Xuid::ResolvePersistentXuid();
|
||||
}
|
||||
// Ensure uid.dat exists from startup (before any multiplayer/login path).
|
||||
Win64Xuid::ResolvePersistentXuid();
|
||||
|
||||
// If no username, let's fall back
|
||||
if (g_Win64Username[0] == 0)
|
||||
@@ -1651,7 +1437,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
MyRegisterClass(hInstance);
|
||||
|
||||
// Perform application initialization:
|
||||
if (!InitInstance (hInstance, launchOptions.serverMode ? SW_HIDE : nCmdShow))
|
||||
if (!InitInstance (hInstance, nCmdShow))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1670,13 +1456,6 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (launchOptions.serverMode)
|
||||
{
|
||||
const int serverResult = RunHeadlessServer();
|
||||
CleanupDevice();
|
||||
return serverResult;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Main message loop
|
||||
MSG msg = {0};
|
||||
@@ -1986,7 +1765,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
}
|
||||
|
||||
// F1 toggles the HUD
|
||||
if (g_KBMInput.IsKeyPressed(VK_F1))
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_TOGGLE_HUD))
|
||||
{
|
||||
const int primaryPad = ProfileManager.GetPrimaryPad();
|
||||
const unsigned char displayHud = app.GetGameSettings(primaryPad, eGameSetting_DisplayHUD);
|
||||
@@ -1995,7 +1774,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
}
|
||||
|
||||
// F3 toggles onscreen debug info
|
||||
if (g_KBMInput.IsKeyPressed(VK_F3))
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
|
||||
{
|
||||
if (const Minecraft* pMinecraft = Minecraft::GetInstance())
|
||||
{
|
||||
@@ -2008,7 +1787,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
|
||||
#ifdef _DEBUG_MENUS_ENABLED
|
||||
// F6 Open debug console
|
||||
if (g_KBMInput.IsKeyPressed(VK_F6))
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_CONSOLE))
|
||||
{
|
||||
static bool s_debugConsole = false;
|
||||
s_debugConsole = !s_debugConsole;
|
||||
@@ -2016,14 +1795,14 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
}
|
||||
#endif
|
||||
|
||||
// F11 Toggle fullscreen
|
||||
if (g_KBMInput.IsKeyPressed(VK_F11))
|
||||
// toggle fullscreen
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_FULLSCREEN))
|
||||
{
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
// TAB opens game info menu. - Vvis :3 - Updated by detectiveren
|
||||
if (g_KBMInput.IsKeyPressed(VK_TAB) && !ui.GetMenuDisplayed(0))
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_HOST_SETTINGS) && !ui.GetMenuDisplayed(0))
|
||||
{
|
||||
if (Minecraft* pMinecraft = Minecraft::GetInstance())
|
||||
{
|
||||
@@ -2035,7 +1814,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
}
|
||||
|
||||
// Open chat
|
||||
if (g_KBMInput.IsKeyPressed('T') && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CHAT) && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
|
||||
{
|
||||
g_KBMInput.ClearCharBuffer();
|
||||
pMinecraft->setScreen(new ChatScreen());
|
||||
|
||||
Binary file not shown.
@@ -8811,4 +8811,7 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
|
||||
<data name="IDS_TOOLTIPS_CURE">
|
||||
<value>Cure</value>
|
||||
</data>
|
||||
<data name="IDS_WINDOWS_EXIT">
|
||||
<value>Exit Minecraft</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
// Auto-generated by StringTable builder — do not edit manually.
|
||||
// Source language: en-US
|
||||
// Total strings: 2286
|
||||
// Total strings: 2287
|
||||
|
||||
#define IDS_NULL 0
|
||||
#define IDS_OK 1
|
||||
@@ -2165,135 +2165,128 @@
|
||||
#define IDS_TUTORIAL_TASK_MINECART_PUSHING 2159
|
||||
#define IDS_CONNECTION_FAILED_NO_SD_SPLITSCREEN 2160
|
||||
#define IDS_TOOLTIPS_CURE 2161
|
||||
#define IDS_LANG_SYSTEM 2162
|
||||
#define IDS_LANG_ENGLISH 2163
|
||||
#define IDS_LANG_GERMAN 2164
|
||||
#define IDS_LANG_SPANISH 2165
|
||||
#define IDS_LANG_SPANISH_SPAIN 2166
|
||||
#define IDS_LANG_SPANISH_LATIN_AMERICA 2167
|
||||
#define IDS_LANG_FRENCH 2168
|
||||
#define IDS_LANG_ITALIAN 2169
|
||||
#define IDS_LANG_PORTUGUESE 2170
|
||||
#define IDS_LANG_PORTUGUESE_PORTUGAL 2171
|
||||
#define IDS_LANG_PORTUGUESE_BRAZIL 2172
|
||||
#define IDS_LANG_JAPANESE 2173
|
||||
#define IDS_LANG_KOREAN 2174
|
||||
#define IDS_LANG_CHINESE_TRADITIONAL 2175
|
||||
#define IDS_LANG_CHINESE_SIMPLIFIED 2176
|
||||
#define IDS_LANG_DANISH 2177
|
||||
#define IDS_LANG_FINISH 2178
|
||||
#define IDS_LANG_DUTCH 2179
|
||||
#define IDS_LANG_POLISH 2180
|
||||
#define IDS_LANG_RUSSIAN 2181
|
||||
#define IDS_LANG_SWEDISH 2182
|
||||
#define IDS_LANG_NORWEGIAN 2183
|
||||
#define IDS_LANG_GREEK 2184
|
||||
#define IDS_LANG_TURKISH 2185
|
||||
#define IDS_LEADERBOARD_KILLS_EASY 2186
|
||||
#define IDS_LEADERBOARD_KILLS_NORMAL 2187
|
||||
#define IDS_LEADERBOARD_KILLS_HARD 2188
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_PEACEFUL 2189
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_EASY 2190
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_NORMAL 2191
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_HARD 2192
|
||||
#define IDS_LEADERBOARD_FARMING_PEACEFUL 2193
|
||||
#define IDS_LEADERBOARD_FARMING_EASY 2194
|
||||
#define IDS_LEADERBOARD_FARMING_NORMAL 2195
|
||||
#define IDS_LEADERBOARD_FARMING_HARD 2196
|
||||
#define IDS_LEADERBOARD_TRAVELLING_PEACEFUL 2197
|
||||
#define IDS_LEADERBOARD_TRAVELLING_EASY 2198
|
||||
#define IDS_LEADERBOARD_TRAVELLING_NORMAL 2199
|
||||
#define IDS_LEADERBOARD_TRAVELLING_HARD 2200
|
||||
#define IDS_TIPS_GAMETIP_0 2201
|
||||
#define IDS_TIPS_GAMETIP_1 2202
|
||||
#define IDS_TIPS_GAMETIP_48 2203
|
||||
#define IDS_TIPS_GAMETIP_44 2204
|
||||
#define IDS_TIPS_GAMETIP_45 2205
|
||||
#define IDS_TIPS_TRIVIA_4 2206
|
||||
#define IDS_TIPS_TRIVIA_17 2207
|
||||
#define IDS_HOW_TO_PLAY_MULTIPLAYER 2208
|
||||
#define IDS_HOW_TO_PLAY_SOCIALMEDIA 2209
|
||||
#define IDS_HOW_TO_PLAY_CREATIVE 2210
|
||||
#define IDS_TUTORIAL_TASK_FLY 2211
|
||||
#define IDS_TOOLTIPS_SELECTDEVICE 2212
|
||||
#define IDS_TOOLTIPS_CHANGEDEVICE 2213
|
||||
#define IDS_TOOLTIPS_VIEW_GAMERCARD 2214
|
||||
#define IDS_TOOLTIPS_VIEW_GAMERPROFILE 2215
|
||||
#define IDS_TOOLTIPS_INVITE_PARTY 2216
|
||||
#define IDS_CONFIRM_START_CREATIVE 2217
|
||||
#define IDS_CONFIRM_START_SAVEDINCREATIVE 2218
|
||||
#define IDS_CONFIRM_START_SAVEDINCREATIVE_CONTINUE 2219
|
||||
#define IDS_CONFIRM_START_HOST_PRIVILEGES 2220
|
||||
#define IDS_CONNECTION_LOST_LIVE 2221
|
||||
#define IDS_CONNECTION_LOST_LIVE_NO_EXIT 2222
|
||||
#define IDS_AWARD_AVATAR1 2223
|
||||
#define IDS_AWARD_AVATAR2 2224
|
||||
#define IDS_AWARD_AVATAR3 2225
|
||||
#define IDS_AWARD_THEME 2226
|
||||
#define IDS_UNLOCK_ACHIEVEMENT_TEXT 2227
|
||||
#define IDS_UNLOCK_AVATAR_TEXT 2228
|
||||
#define IDS_UNLOCK_GAMERPIC_TEXT 2229
|
||||
#define IDS_UNLOCK_THEME_TEXT 2230
|
||||
#define IDS_UNLOCK_ACCEPT_INVITE 2231
|
||||
#define IDS_UNLOCK_GUEST_TEXT 2232
|
||||
#define IDS_LEADERBOARD_GAMERTAG 2233
|
||||
#define IDS_GROUPNAME_POTIONS_480 2234
|
||||
#define IDS_RETURNEDTOTITLESCREEN_TEXT 2235
|
||||
#define IDS_TRIALOVER_TEXT 2236
|
||||
#define IDS_FATAL_ERROR_TEXT 2237
|
||||
#define IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT 2238
|
||||
#define IDS_NO_MULTIPLAYER_PRIVILEGE_HOST_TEXT 2239
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL 2240
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL 2241
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE 2242
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE 2243
|
||||
#define IDS_SAVE_ICON_MESSAGE 2244
|
||||
#define IDS_GAMEOPTION_HOST_PRIVILEGES 2245
|
||||
#define IDS_CHECKBOX_DISPLAY_SPLITSCREENGAMERTAGS 2246
|
||||
#define IDS_ACHIEVEMENTS 2247
|
||||
#define IDS_LABEL_GAMERTAGS 2248
|
||||
#define IDS_IN_GAME_GAMERTAGS 2249
|
||||
#define IDS_SOCIAL_DEFAULT_DESCRIPTION 2250
|
||||
#define IDS_TITLE_UPDATE_NAME 2251
|
||||
#define IDS_PLATFORM_NAME 2252
|
||||
#define IDS_BACK_BUTTON 2253
|
||||
#define IDS_HOST_OPTION_DISABLES_ACHIEVEMENTS 2254
|
||||
#define IDS_KICK_PLAYER_DESCRIPTION 2255
|
||||
#define IDS_USING_TRIAL_TEXUREPACK_WARNING 2256
|
||||
#define IDS_WORLD_SIZE_TITLE_SMALL 2257
|
||||
#define IDS_WORLD_SIZE_TITLE_MEDIUM 2258
|
||||
#define IDS_WORLD_SIZE_TITLE_LARGE 2259
|
||||
#define IDS_WORLD_SIZE_TITLE_CLASSIC 2260
|
||||
#define IDS_WORLD_SIZE 2261
|
||||
#define IDS_GAMEOPTION_WORLD_SIZE 2262
|
||||
#define IDS_DISABLE_SAVING 2263
|
||||
#define IDS_GAMEOPTION_DISABLE_SAVING 2264
|
||||
#define IDS_RICHPRESENCE_GAMESTATE 2265
|
||||
#define IDS_RICHPRESENCE_IDLE 2266
|
||||
#define IDS_RICHPRESENCE_MENUS 2267
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER 2268
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYEROFFLINE 2269
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER_1P 2270
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER_1POFFLINE 2271
|
||||
#define IDS_RICHPRESENCESTATE_BLANK 2272
|
||||
#define IDS_RICHPRESENCESTATE_RIDING_PIG 2273
|
||||
#define IDS_RICHPRESENCESTATE_RIDING_MINECART 2274
|
||||
#define IDS_RICHPRESENCESTATE_BOATING 2275
|
||||
#define IDS_RICHPRESENCESTATE_FISHING 2276
|
||||
#define IDS_RICHPRESENCESTATE_CRAFTING 2277
|
||||
#define IDS_RICHPRESENCESTATE_FORGING 2278
|
||||
#define IDS_RICHPRESENCESTATE_NETHER 2279
|
||||
#define IDS_RICHPRESENCESTATE_CD 2280
|
||||
#define IDS_RICHPRESENCESTATE_MAP 2281
|
||||
#define IDS_RICHPRESENCESTATE_ENCHANTING 2282
|
||||
#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
|
||||
#define IDS_WINDOWS_EXIT 2162
|
||||
#define IDS_LANG_SYSTEM 2163
|
||||
#define IDS_LANG_ENGLISH 2164
|
||||
#define IDS_LANG_GERMAN 2165
|
||||
#define IDS_LANG_SPANISH 2166
|
||||
#define IDS_LANG_SPANISH_SPAIN 2167
|
||||
#define IDS_LANG_SPANISH_LATIN_AMERICA 2168
|
||||
#define IDS_LANG_FRENCH 2169
|
||||
#define IDS_LANG_ITALIAN 2170
|
||||
#define IDS_LANG_PORTUGUESE 2171
|
||||
#define IDS_LANG_PORTUGUESE_PORTUGAL 2172
|
||||
#define IDS_LANG_PORTUGUESE_BRAZIL 2173
|
||||
#define IDS_LANG_JAPANESE 2174
|
||||
#define IDS_LANG_KOREAN 2175
|
||||
#define IDS_LANG_CHINESE_TRADITIONAL 2176
|
||||
#define IDS_LANG_CHINESE_SIMPLIFIED 2177
|
||||
#define IDS_LANG_DANISH 2178
|
||||
#define IDS_LANG_FINISH 2179
|
||||
#define IDS_LANG_DUTCH 2180
|
||||
#define IDS_LANG_POLISH 2181
|
||||
#define IDS_LANG_RUSSIAN 2182
|
||||
#define IDS_LANG_SWEDISH 2183
|
||||
#define IDS_LANG_NORWEGIAN 2184
|
||||
#define IDS_LANG_GREEK 2185
|
||||
#define IDS_LANG_TURKISH 2186
|
||||
#define IDS_LEADERBOARD_KILLS_EASY 2187
|
||||
#define IDS_LEADERBOARD_KILLS_NORMAL 2188
|
||||
#define IDS_LEADERBOARD_KILLS_HARD 2189
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_PEACEFUL 2190
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_EASY 2191
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_NORMAL 2192
|
||||
#define IDS_LEADERBOARD_MINING_BLOCKS_HARD 2193
|
||||
#define IDS_LEADERBOARD_FARMING_PEACEFUL 2194
|
||||
#define IDS_LEADERBOARD_FARMING_EASY 2195
|
||||
#define IDS_LEADERBOARD_FARMING_NORMAL 2196
|
||||
#define IDS_LEADERBOARD_FARMING_HARD 2197
|
||||
#define IDS_LEADERBOARD_TRAVELLING_PEACEFUL 2198
|
||||
#define IDS_LEADERBOARD_TRAVELLING_EASY 2199
|
||||
#define IDS_LEADERBOARD_TRAVELLING_NORMAL 2200
|
||||
#define IDS_LEADERBOARD_TRAVELLING_HARD 2201
|
||||
#define IDS_TIPS_GAMETIP_0 2202
|
||||
#define IDS_TIPS_GAMETIP_1 2203
|
||||
#define IDS_TIPS_GAMETIP_48 2204
|
||||
#define IDS_TIPS_GAMETIP_44 2205
|
||||
#define IDS_TIPS_GAMETIP_45 2206
|
||||
#define IDS_TIPS_TRIVIA_4 2207
|
||||
#define IDS_TIPS_TRIVIA_17 2208
|
||||
#define IDS_HOW_TO_PLAY_MULTIPLAYER 2209
|
||||
#define IDS_HOW_TO_PLAY_SOCIALMEDIA 2210
|
||||
#define IDS_HOW_TO_PLAY_CREATIVE 2211
|
||||
#define IDS_TUTORIAL_TASK_FLY 2212
|
||||
#define IDS_TOOLTIPS_SELECTDEVICE 2213
|
||||
#define IDS_TOOLTIPS_CHANGEDEVICE 2214
|
||||
#define IDS_TOOLTIPS_VIEW_GAMERCARD 2215
|
||||
#define IDS_TOOLTIPS_VIEW_GAMERPROFILE 2216
|
||||
#define IDS_TOOLTIPS_INVITE_PARTY 2217
|
||||
#define IDS_CONFIRM_START_CREATIVE 2218
|
||||
#define IDS_CONFIRM_START_SAVEDINCREATIVE 2219
|
||||
#define IDS_CONFIRM_START_SAVEDINCREATIVE_CONTINUE 2220
|
||||
#define IDS_CONFIRM_START_HOST_PRIVILEGES 2221
|
||||
#define IDS_CONNECTION_LOST_LIVE 2222
|
||||
#define IDS_CONNECTION_LOST_LIVE_NO_EXIT 2223
|
||||
#define IDS_AWARD_AVATAR1 2224
|
||||
#define IDS_AWARD_AVATAR2 2225
|
||||
#define IDS_AWARD_AVATAR3 2226
|
||||
#define IDS_AWARD_THEME 2227
|
||||
#define IDS_UNLOCK_ACHIEVEMENT_TEXT 2228
|
||||
#define IDS_UNLOCK_AVATAR_TEXT 2229
|
||||
#define IDS_UNLOCK_GAMERPIC_TEXT 2230
|
||||
#define IDS_UNLOCK_THEME_TEXT 2231
|
||||
#define IDS_UNLOCK_ACCEPT_INVITE 2232
|
||||
#define IDS_UNLOCK_GUEST_TEXT 2233
|
||||
#define IDS_LEADERBOARD_GAMERTAG 2234
|
||||
#define IDS_GROUPNAME_POTIONS_480 2235
|
||||
#define IDS_RETURNEDTOTITLESCREEN_TEXT 2236
|
||||
#define IDS_TRIALOVER_TEXT 2237
|
||||
#define IDS_FATAL_ERROR_TEXT 2238
|
||||
#define IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT 2239
|
||||
#define IDS_NO_MULTIPLAYER_PRIVILEGE_HOST_TEXT 2240
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL 2241
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL 2242
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE 2243
|
||||
#define IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE 2244
|
||||
#define IDS_SAVE_ICON_MESSAGE 2245
|
||||
#define IDS_GAMEOPTION_HOST_PRIVILEGES 2246
|
||||
#define IDS_CHECKBOX_DISPLAY_SPLITSCREENGAMERTAGS 2247
|
||||
#define IDS_ACHIEVEMENTS 2248
|
||||
#define IDS_LABEL_GAMERTAGS 2249
|
||||
#define IDS_IN_GAME_GAMERTAGS 2250
|
||||
#define IDS_SOCIAL_DEFAULT_DESCRIPTION 2251
|
||||
#define IDS_TITLE_UPDATE_NAME 2252
|
||||
#define IDS_PLATFORM_NAME 2253
|
||||
#define IDS_BACK_BUTTON 2254
|
||||
#define IDS_HOST_OPTION_DISABLES_ACHIEVEMENTS 2255
|
||||
#define IDS_KICK_PLAYER_DESCRIPTION 2256
|
||||
#define IDS_USING_TRIAL_TEXUREPACK_WARNING 2257
|
||||
#define IDS_WORLD_SIZE_TITLE_SMALL 2258
|
||||
#define IDS_WORLD_SIZE_TITLE_MEDIUM 2259
|
||||
#define IDS_WORLD_SIZE_TITLE_LARGE 2260
|
||||
#define IDS_WORLD_SIZE_TITLE_CLASSIC 2261
|
||||
#define IDS_WORLD_SIZE 2262
|
||||
#define IDS_GAMEOPTION_WORLD_SIZE 2263
|
||||
#define IDS_DISABLE_SAVING 2264
|
||||
#define IDS_GAMEOPTION_DISABLE_SAVING 2265
|
||||
#define IDS_RICHPRESENCE_GAMESTATE 2266
|
||||
#define IDS_RICHPRESENCE_IDLE 2267
|
||||
#define IDS_RICHPRESENCE_MENUS 2268
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER 2269
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYEROFFLINE 2270
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER_1P 2271
|
||||
#define IDS_RICHPRESENCE_MULTIPLAYER_1POFFLINE 2272
|
||||
#define IDS_RICHPRESENCESTATE_BLANK 2273
|
||||
#define IDS_RICHPRESENCESTATE_RIDING_PIG 2274
|
||||
#define IDS_RICHPRESENCESTATE_RIDING_MINECART 2275
|
||||
#define IDS_RICHPRESENCESTATE_BOATING 2276
|
||||
#define IDS_RICHPRESENCESTATE_FISHING 2277
|
||||
#define IDS_RICHPRESENCESTATE_CRAFTING 2278
|
||||
#define IDS_RICHPRESENCESTATE_FORGING 2279
|
||||
#define IDS_RICHPRESENCESTATE_NETHER 2280
|
||||
#define IDS_RICHPRESENCESTATE_CD 2281
|
||||
#define IDS_RICHPRESENCESTATE_MAP 2282
|
||||
#define IDS_RICHPRESENCESTATE_ENCHANTING 2283
|
||||
#define IDS_RICHPRESENCESTATE_BREWING 2284
|
||||
#define IDS_RICHPRESENCESTATE_ANVIL 2285
|
||||
#define IDS_RICHPRESENCESTATE_TRADING 2286
|
||||
|
||||
@@ -30,7 +30,7 @@ void Bat::defineSynchedData()
|
||||
|
||||
float Bat::getSoundVolume()
|
||||
{
|
||||
return 0.1f;
|
||||
return 0.8f;
|
||||
}
|
||||
|
||||
float Bat::getVoicePitch()
|
||||
|
||||
@@ -838,51 +838,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ void Cow::playStepSound(int xt, int yt, int zt, int t)
|
||||
|
||||
float Cow::getSoundVolume()
|
||||
{
|
||||
return 0.4f;
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
int Cow::getDeathLoot()
|
||||
|
||||
@@ -50,7 +50,6 @@ 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
|
||||
@@ -72,4 +71,3 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -96,9 +96,20 @@ int Entity::getSmallId()
|
||||
puiUsedFlags++;
|
||||
}
|
||||
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
// in mc server dedi, a server with 8+ playerrs can cause this to go wack
|
||||
int fallbackId = Entity::entityCounter++;
|
||||
|
||||
if (entityCounter == 0x7ffffff)
|
||||
{
|
||||
entityCounter = 2048;
|
||||
}
|
||||
return fallbackId;
|
||||
#else
|
||||
app.DebugPrintf("Out of small entity Ids... possible leak?\n");
|
||||
__debugbreak();
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Entity::countFlagsForPIX()
|
||||
|
||||
@@ -37,6 +37,7 @@ void FireworksRecipe::ReleaseThreadStorage()
|
||||
void FireworksRecipe::setResultItem(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
ThreadStorage *tls = static_cast<ThreadStorage *>(TlsGetValue(tlsIdx));
|
||||
if (tls == nullptr) tls = tlsDefault;
|
||||
tls->resultItem = item;
|
||||
}
|
||||
|
||||
@@ -269,6 +270,7 @@ bool FireworksRecipe::matches(shared_ptr<CraftingContainer> craftSlots, Level *l
|
||||
shared_ptr<ItemInstance> FireworksRecipe::assemble(shared_ptr<CraftingContainer> craftSlots)
|
||||
{
|
||||
ThreadStorage *tls = static_cast<ThreadStorage *>(TlsGetValue(tlsIdx));
|
||||
if (tls == nullptr) tls = tlsDefault;
|
||||
return tls->resultItem->copy();
|
||||
//return resultItem->copy();
|
||||
}
|
||||
@@ -281,6 +283,7 @@ int FireworksRecipe::size()
|
||||
const ItemInstance *FireworksRecipe::getResultItem()
|
||||
{
|
||||
ThreadStorage *tls = static_cast<ThreadStorage *>(TlsGetValue(tlsIdx));
|
||||
if (tls == nullptr) tls = tlsDefault;
|
||||
return tls->resultItem.get();
|
||||
//return resultItem.get();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,12 @@ using namespace std;
|
||||
|
||||
// 4J Stu - This value should be big enough that we don't get any crashes causes by memory overwrites,
|
||||
// however it does seem way too large for what is actually needed. Needs further investigation
|
||||
#ifdef MINECRAFT_SERVER_BUILD
|
||||
// fixes a crash when 8+ players are present
|
||||
#define LEVEL_CHUNKS_TO_UPDATE_MAX (32*32*8)
|
||||
#else
|
||||
#define LEVEL_CHUNKS_TO_UPDATE_MAX (19*19*8)
|
||||
#endif
|
||||
|
||||
class Vec3;
|
||||
class ChunkSource;
|
||||
|
||||
@@ -34,7 +34,6 @@ LoginPacket::LoginPacket()
|
||||
m_uiGamePrivileges = 0;
|
||||
m_xzSize = LEVEL_MAX_WIDTH;
|
||||
m_hellScale = HELL_LEVEL_MAX_SCALE;
|
||||
m_isHardcore = false;
|
||||
}
|
||||
|
||||
// Client -> Server
|
||||
@@ -64,11 +63,10 @@ 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, bool isHardcore)
|
||||
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)
|
||||
{
|
||||
this->userName = userName;
|
||||
this->clientVersion = clientVersion;
|
||||
@@ -94,7 +92,6 @@ 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
|
||||
@@ -109,8 +106,6 @@ 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();
|
||||
@@ -149,7 +144,7 @@ void LoginPacket::write(DataOutputStream *dos) //throws IOException
|
||||
writeUtf(m_pLevelType->getGeneratorName(), dos);
|
||||
}
|
||||
dos->writeLong(seed);
|
||||
dos->writeInt(gameType | (m_isHardcore ? 0x8 : 0));
|
||||
dos->writeInt(gameType);
|
||||
dos->writeByte(dimension);
|
||||
dos->writeByte(mapHeight);
|
||||
dos->writeByte(maxPlayers);
|
||||
|
||||
@@ -24,7 +24,6 @@ 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;
|
||||
@@ -32,7 +31,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, bool isHardcore = false); // 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); // 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,10 +17,9 @@ 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, bool isHardcore)
|
||||
RespawnPacket::RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale)
|
||||
{
|
||||
this->dimension = dimension;
|
||||
this->mapSeed = mapSeed;
|
||||
@@ -32,7 +31,6 @@ 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);
|
||||
|
||||
}
|
||||
@@ -45,9 +43,7 @@ void RespawnPacket::handle(PacketListener *listener)
|
||||
void RespawnPacket::read(DataInputStream *dis) //throws IOException
|
||||
{
|
||||
dimension = dis->readByte();
|
||||
int rawGameType = dis->readByte();
|
||||
m_isHardcore = (rawGameType & 0x8) != 0;
|
||||
playerGameType = GameType::byId(rawGameType & ~0x8);
|
||||
playerGameType = GameType::byId(dis->readByte());
|
||||
mapHeight = dis->readShort();
|
||||
wstring typeName = readUtf(dis, 16);
|
||||
m_pLevelType = LevelType::getLevelType(typeName);
|
||||
@@ -70,7 +66,7 @@ void RespawnPacket::read(DataInputStream *dis) //throws IOException
|
||||
void RespawnPacket::write(DataOutputStream *dos) //throws IOException
|
||||
{
|
||||
dos->writeByte(dimension);
|
||||
dos->writeByte(playerGameType->getId() | (m_isHardcore ? 0x8 : 0));
|
||||
dos->writeByte(playerGameType->getId());
|
||||
dos->writeShort(mapHeight);
|
||||
if (m_pLevelType == nullptr)
|
||||
{
|
||||
|
||||
@@ -19,10 +19,9 @@ 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, bool isHardcore = false);
|
||||
RespawnPacket(char dimension, int64_t mapSeed, int mapHeight, GameType *playerGameType, char difficulty, LevelType *pLevelType, bool newSeaLevel, int newEntityId, int xzSize, int hellScale);
|
||||
|
||||
virtual void handle(PacketListener *listener);
|
||||
virtual void read(DataInputStream *dis);
|
||||
|
||||
@@ -30,6 +30,65 @@ ensure_persist_file() {
|
||||
ln -sfn "${persist_path}" "${runtime_path}"
|
||||
}
|
||||
|
||||
wait_for_xvfb_ready() {
|
||||
local display="$1"
|
||||
local xvfb_pid="$2"
|
||||
local wait_seconds="${XVFB_WAIT_SECONDS:-10}"
|
||||
local wait_ticks=$((wait_seconds * 10))
|
||||
local display_number="${display#:}"
|
||||
display_number="${display_number%%.*}"
|
||||
|
||||
if [ -z "${display_number}" ] || ! [[ "${display_number}" =~ ^[0-9]+$ ]]; then
|
||||
echo "[error] Invalid DISPLAY format for Xvfb wait: ${display}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local socket_path="/tmp/.X11-unix/X${display_number}"
|
||||
local elapsed=0
|
||||
|
||||
while [ "${elapsed}" -lt "${wait_ticks}" ]; do
|
||||
if ! kill -0 "${xvfb_pid}" 2>/dev/null; then
|
||||
echo "[error] Xvfb exited before the display became ready." >&2
|
||||
if [ -f /tmp/xvfb.log ]; then
|
||||
echo "[error] ---- /tmp/xvfb.log ----" >&2
|
||||
tail -n 200 /tmp/xvfb.log >&2 || true
|
||||
echo "[error] ----------------------" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -S "${socket_path}" ]; then
|
||||
# Keep a short extra delay so Wine does not race display handshake.
|
||||
sleep 0.2
|
||||
if kill -0 "${xvfb_pid}" 2>/dev/null && [ -S "${socket_path}" ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# One more liveness check after the ready probe branch.
|
||||
if ! kill -0 "${xvfb_pid}" 2>/dev/null; then
|
||||
echo "[error] Xvfb exited during display readiness probe." >&2
|
||||
if [ -f /tmp/xvfb.log ]; then
|
||||
echo "[error] ---- /tmp/xvfb.log ----" >&2
|
||||
tail -n 200 /tmp/xvfb.log >&2 || true
|
||||
echo "[error] ----------------------" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
|
||||
echo "[error] Timed out waiting for Xvfb display ${display}." >&2
|
||||
if [ -f /tmp/xvfb.log ]; then
|
||||
echo "[error] ---- /tmp/xvfb.log ----" >&2
|
||||
tail -n 200 /tmp/xvfb.log >&2 || true
|
||||
echo "[error] ----------------------" >&2
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ ! -d "$SERVER_DIR" ]; then
|
||||
echo "[error] Server directory not found: $SERVER_DIR" >&2
|
||||
exit 1
|
||||
@@ -78,8 +137,25 @@ fi
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
export DISPLAY="${XVFB_DISPLAY:-:99}"
|
||||
XVFB_SCREEN="${XVFB_SCREEN:-64x64x16}"
|
||||
DISPLAY_NUMBER="${DISPLAY#:}"
|
||||
DISPLAY_NUMBER="${DISPLAY_NUMBER%%.*}"
|
||||
if [ -z "${DISPLAY_NUMBER}" ] || ! [[ "${DISPLAY_NUMBER}" =~ ^[0-9]+$ ]]; then
|
||||
echo "[error] Invalid XVFB_DISPLAY format: ${DISPLAY}" >&2
|
||||
exit 1
|
||||
fi
|
||||
XVFB_SOCKET="/tmp/.X11-unix/X${DISPLAY_NUMBER}"
|
||||
XVFB_LOCK="/tmp/.X${DISPLAY_NUMBER}-lock"
|
||||
# The check is performed assuming the same container will be restarted.
|
||||
if [ -S "${XVFB_SOCKET}" ] || [ -e "${XVFB_LOCK}" ]; then
|
||||
echo "[warn] Removing stale Xvfb state for ${DISPLAY} before startup." >&2
|
||||
rm -f "${XVFB_SOCKET}" "${XVFB_LOCK}"
|
||||
fi
|
||||
Xvfb "${DISPLAY}" -nolisten tcp -screen 0 "${XVFB_SCREEN}" >/tmp/xvfb.log 2>&1 &
|
||||
sleep 0.2
|
||||
XVFB_PID=$!
|
||||
wait_for_xvfb_ready "${DISPLAY}" "${XVFB_PID}"
|
||||
echo "[info] Xvfb ready on ${DISPLAY} (pid=${XVFB_PID}, screen=${XVFB_SCREEN})"
|
||||
else
|
||||
echo "[info] Using existing DISPLAY=${DISPLAY}; skipping Xvfb startup"
|
||||
fi
|
||||
|
||||
args=(
|
||||
|
||||
Reference in New Issue
Block a user