aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
diff options
context:
space:
mode:
authorqwasdrizzel <145519042+qwasdrizzel@users.noreply.github.com>2026-03-16 21:44:26 -0500
committerGitHub <noreply@github.com>2026-03-16 21:44:26 -0500
commitce739f6045ec72127491286ea3f3f21e537c1b55 (patch)
treef33bd42a47c1b4a7b2153a7fb77127ee3b407db9 /Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
parent255a18fe8e9b57377975f82e2b227afe2a12eda0 (diff)
parent5a59f5d146b43811dde6a5a0245ee9875d7b5cd1 (diff)
Merge branch 'smartcmd:main' into main
Diffstat (limited to 'Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp')
-rw-r--r--Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp483
1 files changed, 386 insertions, 97 deletions
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
index 8664aca1..d73148f5 100644
--- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
@@ -36,13 +36,13 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
if (slashPos != wstring::npos)
{
wstring sidecarPath = filePath.substr(0, slashPos + 1) + L"worldname.txt";
- FILE *fr = NULL;
+ FILE *fr = nullptr;
if (_wfopen_s(&fr, sidecarPath.c_str(), L"r") == 0 && fr)
{
char buf[128] = {};
if (fgets(buf, sizeof(buf), fr))
{
- int len = (int)strlen(buf);
+ int len = static_cast<int>(strlen(buf));
while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r' || buf[len-1] == ' '))
buf[--len] = '\0';
fclose(fr);
@@ -57,15 +57,15 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
}
}
- HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (hFile == INVALID_HANDLE_VALUE) return L"";
- DWORD fileSize = GetFileSize(hFile, NULL);
+ DWORD fileSize = GetFileSize(hFile, nullptr);
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) { CloseHandle(hFile); return L""; }
unsigned char *rawData = new unsigned char[fileSize];
DWORD bytesRead = 0;
- if (!ReadFile(hFile, rawData, fileSize, &bytesRead, NULL) || bytesRead != fileSize)
+ if (!ReadFile(hFile, rawData, fileSize, &bytesRead, nullptr) || bytesRead != fileSize)
{
CloseHandle(hFile);
delete[] rawData;
@@ -73,7 +73,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
}
CloseHandle(hFile);
- unsigned char *saveData = NULL;
+ unsigned char *saveData = nullptr;
unsigned int saveSize = 0;
bool freeSaveData = false;
@@ -120,10 +120,10 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath)
ba.data = (byte*)(saveData + off);
ba.length = len;
CompoundTag *root = NbtIo::decompress(ba);
- if (root != NULL)
+ if (root != nullptr)
{
CompoundTag *dataTag = root->getCompound(L"Data");
- if (dataTag != NULL)
+ if (dataTag != nullptr)
result = dataTag->getString(L"LevelName");
delete root;
}
@@ -172,7 +172,7 @@ C4JStorage::SAVETRANSFER_FILE_DETAILS UIScene_LoadOrJoinMenu::m_debugTransferDet
int UIScene_LoadOrJoinMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes)
{
- UIScene_LoadOrJoinMenu *pClass= (UIScene_LoadOrJoinMenu *)lpParam;
+ UIScene_LoadOrJoinMenu *pClass= static_cast<UIScene_LoadOrJoinMenu *>(lpParam);
app.DebugPrintf("Received data for save thumbnail\n");
@@ -184,9 +184,9 @@ int UIScene_LoadOrJoinMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE p
}
else
{
- pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].pbThumbnailData = NULL;
+ pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].pbThumbnailData = nullptr;
pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].dwThumbnailSize = 0;
- app.DebugPrintf("Save thumbnail data is NULL, or has size 0\n");
+ app.DebugPrintf("Save thumbnail data is nullptr, or has size 0\n");
}
pClass->m_bSaveThumbnailReady = true;
@@ -215,7 +215,7 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
m_bIgnoreInput = false;
m_bShowingPartyGamesOnly = false;
m_bInParty = false;
- m_currentSessions = NULL;
+ m_currentSessions = nullptr;
m_iState=e_SavesIdle;
//m_bRetrievingSaveInfo=false;
@@ -239,9 +239,9 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
m_bRetrievingSaveThumbnails = false;
m_bSaveThumbnailReady = false;
m_bExitScene=false;
- m_pSaveDetails=NULL;
+ m_pSaveDetails=nullptr;
m_bSavesDisplayed=false;
- m_saveDetails = NULL;
+ m_saveDetails = nullptr;
m_iSaveDetailsCount = 0;
m_iTexturePacksNotInstalled = 0;
m_bCopying = false;
@@ -320,7 +320,7 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
#ifdef _XBOX
// 4J-PB - there may be texture packs we don't have, so use the info from TMS for this
- DLC_INFO *pDLCInfo=NULL;
+ DLC_INFO *pDLCInfo=nullptr;
// first pass - look to see if there are any that are not in the list
bool bTexturePackAlreadyListed;
@@ -399,11 +399,16 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
UIScene_LoadOrJoinMenu::~UIScene_LoadOrJoinMenu()
{
- g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL );
+ g_NetworkManager.SetSessionsUpdatedCallback( nullptr, nullptr );
app.SetLiveLinkRequired( false );
- delete m_currentSessions;
- m_currentSessions = NULL;
+ if (m_currentSessions)
+ {
+ for (const auto& it : *m_currentSessions)
+ delete it;
+ delete m_currentSessions;
+ m_currentSessions = nullptr;
+ }
#if TO_BE_IMPLEMENTED
// Reset the background downloading, in case we changed it by attempting to download a texture pack
@@ -520,6 +525,9 @@ void UIScene_LoadOrJoinMenu::Initialise()
{
m_iSaveListIndex = 0;
m_iGameListIndex = 0;
+#ifdef _WINDOWS64
+ m_addServerPhase = eAddServer_Idle;
+#endif
m_iDefaultButtonsC = 0;
m_iMashUpButtonsC=0;
@@ -705,7 +713,7 @@ void UIScene_LoadOrJoinMenu::tick()
if(!m_bSavesDisplayed)
{
m_pSaveDetails=StorageManager.ReturnSavesInfo();
- if(m_pSaveDetails!=NULL)
+ if(m_pSaveDetails!=nullptr)
{
//CD - Fix - Adding define for ORBIS/XBOXONE
#if defined(_XBOX_ONE) || defined(__ORBIS__)
@@ -716,11 +724,11 @@ void UIScene_LoadOrJoinMenu::tick()
m_bSavesDisplayed=true;
UpdateGamesList();
- if(m_saveDetails!=NULL)
+ if(m_saveDetails!=nullptr)
{
for(unsigned int i = 0; i < m_iSaveDetailsCount; ++i)
{
- if(m_saveDetails[i].pbThumbnailData!=NULL)
+ if(m_saveDetails[i].pbThumbnailData!=nullptr)
{
delete m_saveDetails[i].pbThumbnailData;
}
@@ -1000,9 +1008,9 @@ void UIScene_LoadOrJoinMenu::GetSaveInfo()
#ifdef __ORBIS__
// We need to make sure this is non-null so that we have an idea of free space
m_pSaveDetails=StorageManager.ReturnSavesInfo();
- if(m_pSaveDetails==NULL)
+ if(m_pSaveDetails==nullptr)
{
- C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad,NULL,this,"save");
+ C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad,nullptr,this,"save");
}
#endif
@@ -1015,7 +1023,7 @@ void UIScene_LoadOrJoinMenu::GetSaveInfo()
if( savesDir.exists() )
{
m_saves = savesDir.listFiles();
- uiSaveC = (unsigned int)m_saves->size();
+ uiSaveC = static_cast<unsigned int>(m_saves->size());
}
// add the New Game and Tutorial after the saves list is retrieved, if there are any saves
@@ -1049,9 +1057,9 @@ void UIScene_LoadOrJoinMenu::GetSaveInfo()
m_controlSavesTimer.setVisible(true);
m_pSaveDetails=StorageManager.ReturnSavesInfo();
- if(m_pSaveDetails==NULL)
+ if(m_pSaveDetails==nullptr)
{
- C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad,NULL,this,"save");
+ C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad, nullptr,this,"save");
}
#if TO_BE_IMPLEMENTED
@@ -1169,6 +1177,43 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
}
}
#endif
+#ifdef _WINDOWS64
+ // Right click on a save opens save options (same as RB / ACTION_MENU_RIGHT_SCROLL)
+ if(pressed && !repeat && ProfileManager.IsFullVersion() && !StorageManager.GetSaveDisabled())
+ {
+ if(DoesSavesListHaveFocus() && (m_iDefaultButtonsC > 0) && (m_iSaveListIndex >= m_iDefaultButtonsC))
+ {
+ m_bIgnoreInput = true;
+ if(StorageManager.EnoughSpaceForAMinSaveGame())
+ {
+ UINT uiIDA[3];
+ uiIDA[0]=IDS_CONFIRM_CANCEL;
+ uiIDA[1]=IDS_TITLE_RENAMESAVE;
+ uiIDA[2]=IDS_TOOLTIPS_DELETESAVE;
+ ui.RequestAlertMessage(IDS_TOOLTIPS_SAVEOPTIONS, IDS_TEXT_SAVEOPTIONS, uiIDA, 3, iPad,&UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned,this);
+ }
+ else
+ {
+ UINT uiIDA[2];
+ uiIDA[0]=IDS_CONFIRM_CANCEL;
+ uiIDA[1]=IDS_CONFIRM_OK;
+ ui.RequestAlertMessage(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, iPad,&UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned,this);
+ }
+ ui.PlayUISFX(eSFX_Press);
+ }
+ else if(DoesMashUpWorldHaveFocus() && (m_iSaveListIndex != JOIN_LOAD_CREATE_BUTTON_INDEX))
+ {
+ LevelGenerationOptions *levelGen = m_generators.at(m_iSaveListIndex - 1);
+ if(!levelGen->isTutorial() && levelGen->requiresTexturePack())
+ {
+ m_bIgnoreInput = true;
+ app.HideMashupPackWorld(m_iPad, levelGen->getRequiredTexturePackId());
+ m_iState = e_SavesRepopulateAfterMashupHide;
+ }
+ ui.PlayUISFX(eSFX_Press);
+ }
+ }
+#endif
break;
case ACTION_MENU_Y:
#if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__)
@@ -1353,7 +1398,7 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,bool bRes)
{
// 4J HEG - No reason to set value if keyboard was cancelled
- UIScene_LoadOrJoinMenu *pClass=(UIScene_LoadOrJoinMenu *)lpParam;
+ UIScene_LoadOrJoinMenu *pClass=static_cast<UIScene_LoadOrJoinMenu *>(lpParam);
pClass->m_bIgnoreInput=false;
if (bRes)
{
@@ -1378,7 +1423,7 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
// Convert the ui16Text input to a wide string
wchar_t wNewName[128] = {};
for (int k = 0; k < 127 && ui16Text[k]; k++)
- wNewName[k] = (wchar_t)ui16Text[k];
+ wNewName[k] = static_cast<wchar_t>(ui16Text[k]);
// Convert to narrow for storage and in-memory update
char narrowName[128] = {};
@@ -1389,7 +1434,7 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
mbstowcs(wFilename, pClass->m_saveDetails[listPos].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
wstring sidecarPath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\worldname.txt");
- FILE *fw = NULL;
+ FILE *fw = nullptr;
if (_wfopen_s(&fw, sidecarPath.c_str(), L"w") == 0 && fw)
{
fputs(narrowName, fw);
@@ -1422,18 +1467,22 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
}
void UIScene_LoadOrJoinMenu::handleInitFocus(F64 controlId, F64 childId)
{
- app.DebugPrintf(app.USER_SR, "UIScene_LoadOrJoinMenu::handleInitFocus - %d , %d\n", (int)controlId, (int)childId);
+ app.DebugPrintf(app.USER_SR, "UIScene_LoadOrJoinMenu::handleInitFocus - %d , %d\n", static_cast<int>(controlId), static_cast<int>(childId));
}
void UIScene_LoadOrJoinMenu::handleFocusChange(F64 controlId, F64 childId)
{
- app.DebugPrintf(app.USER_SR, "UIScene_LoadOrJoinMenu::handleFocusChange - %d , %d\n", (int)controlId, (int)childId);
+ app.DebugPrintf(app.USER_SR, "UIScene_LoadOrJoinMenu::handleFocusChange - %d , %d\n", static_cast<int>(controlId), static_cast<int>(childId));
- switch((int)controlId)
+ switch(static_cast<int>(controlId))
{
case eControl_GamesList:
m_iGameListIndex = childId;
- m_buttonListGames.updateChildFocus( (int) childId );
+#ifdef _WINDOWS64
+ // Offset past the "Add Server" button so m_iGameListIndex is a session index
+ m_iGameListIndex -= 1;
+#endif
+ m_buttonListGames.updateChildFocus( static_cast<int>(childId) );
break;
case eControl_SavesList:
m_iSaveListIndex = childId;
@@ -1455,18 +1504,18 @@ void UIScene_LoadOrJoinMenu::remoteStorageGetSaveCallback(LPVOID lpParam, SonyRe
void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
{
- switch((int)controlId)
+ switch(static_cast<int>(controlId))
{
case eControl_SavesList:
{
m_bIgnoreInput=true;
- int lGenID = (int)childId - 1;
+ int lGenID = static_cast<int>(childId) - 1;
//CD - Added for audio
ui.PlayUISFX(eSFX_Press);
- if((int)childId == JOIN_LOAD_CREATE_BUTTON_INDEX)
+ if(static_cast<int>(childId) == JOIN_LOAD_CREATE_BUTTON_INDEX)
{
app.SetTutorialMode( false );
@@ -1497,7 +1546,7 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
params->iSaveGameInfoIndex=-1;
//params->pbSaveRenamed=&m_bSaveRenamed;
params->levelGen = levelGen;
- params->saveDetails = NULL;
+ params->saveDetails = nullptr;
// navigate to the settings scene
ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadMenu, params);
@@ -1508,7 +1557,7 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
#ifdef __ORBIS__
// check if this is a damaged save
PSAVE_INFO pSaveInfo = &m_pSaveDetails->SaveInfoA[((int)childId)-m_iDefaultButtonsC];
- if(pSaveInfo->thumbnailData == NULL && pSaveInfo->modifiedTime == 0) // no thumbnail data and time of zero and zero blocks useset for corrupt files
+ if(pSaveInfo->thumbnailData == nullptr && pSaveInfo->modifiedTime == 0) // no thumbnail data and time of zero and zero blocks useset for corrupt files
{
// give the option to delete the save
UINT uiIDA[2];
@@ -1524,17 +1573,17 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled())
{
- LoadSaveFromDisk(m_saves->at((int)childId-m_iDefaultButtonsC));
+ LoadSaveFromDisk(m_saves->at(static_cast<int>(childId)-m_iDefaultButtonsC));
}
else
{
LoadMenuInitData *params = new LoadMenuInitData();
params->iPad = m_iPad;
// need to get the iIndex from the list item, since the position in the list doesn't correspond to the GetSaveGameInfo list because of sorting
- params->iSaveGameInfoIndex=m_saveDetails[((int)childId)-m_iDefaultButtonsC].saveId;
+ params->iSaveGameInfoIndex=m_saveDetails[static_cast<int>(childId)-m_iDefaultButtonsC].saveId;
//params->pbSaveRenamed=&m_bSaveRenamed;
- params->levelGen = NULL;
- params->saveDetails = &m_saveDetails[ ((int)childId)-m_iDefaultButtonsC ];
+ params->levelGen = nullptr;
+ params->saveDetails = &m_saveDetails[ static_cast<int>(childId)-m_iDefaultButtonsC ];
#ifdef _XBOX_ONE
// On XB1, saves might need syncing, in which case inform the user so they can decide whether they want to wait for this to happen
@@ -1560,6 +1609,14 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
break;
case eControl_GamesList:
{
+#ifdef _WINDOWS64
+ if (static_cast<int>(childId) == ADD_SERVER_BUTTON_INDEX)
+ {
+ ui.PlayUISFX(eSFX_Press);
+ BeginAddServer();
+ break;
+ }
+#endif
m_bIgnoreInput=true;
m_eAction = eAction_JoinGame;
@@ -1568,7 +1625,11 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
ui.PlayUISFX(eSFX_Press);
{
- int nIndex = (int)childId;
+ int nIndex = static_cast<int>(childId);
+#ifdef _WINDOWS64
+ // Offset by 1 because the "Add Server" button is at index 0
+ nIndex -= 1;
+#endif
m_iGameListIndex = nIndex;
CheckAndJoinGame(nIndex);
}
@@ -1588,7 +1649,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
bool bContentRestricted=false;
// we're online, since we are joining a game
- ProfileManager.GetChatAndContentRestrictions(m_iPad,true,&noUGC,&bContentRestricted,NULL);
+ ProfileManager.GetChatAndContentRestrictions(m_iPad,true,&noUGC,&bContentRestricted,nullptr);
#ifdef __ORBIS__
// 4J Stu - On PS4 we don't restrict playing multiplayer based on chat restriction, so remove this check
@@ -1632,7 +1693,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
UINT uiIDA[1];
uiIDA[0]=IDS_CONFIRM_OK;
// Not allowed to play online
- ui.RequestAlertMessage(IDS_ONLINE_GAME, IDS_CHAT_RESTRICTION_UGC, uiIDA, 1, m_iPad,NULL,this);
+ ui.RequestAlertMessage(IDS_ONLINE_GAME, IDS_CHAT_RESTRICTION_UGC, uiIDA, 1, m_iPad,nullptr,this);
#else
// Not allowed to play online
ProfileManager.ShowSystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, 0 );
@@ -1677,7 +1738,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
// MGH - added this so we don't try and upsell when we don't know if the player has PS Plus yet (if it can't connect to the PS Plus server).
UINT uiIDA[1];
uiIDA[0]=IDS_OK;
- ui.RequestAlertMessage(IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL);
+ ui.RequestAlertMessage(IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), nullptr, nullptr);
return;
}
@@ -1697,7 +1758,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
// UINT uiIDA[2];
// uiIDA[0]=IDS_CONFIRM_OK;
// uiIDA[1]=IDS_PLAYSTATIONPLUS_SIGNUP;
- // ui.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_PLAYSTATIONPLUS, uiIDA,2,ProfileManager.GetPrimaryPad(),&UIScene_LoadOrJoinMenu::PSPlusReturned,this, app.GetStringTable(),NULL,0,false);
+ // ui.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_PLAYSTATIONPLUS, uiIDA,2,ProfileManager.GetPrimaryPad(),&UIScene_LoadOrJoinMenu::PSPlusReturned,this, app.GetStringTable(),nullptr,0,false);
m_bIgnoreInput=false;
return;
@@ -1706,12 +1767,34 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
#endif
#endif
- //CScene_MultiGameInfo::JoinMenuInitData *initData = new CScene_MultiGameInfo::JoinMenuInitData();
m_initData->iPad = 0;;
m_initData->selectedSession = m_currentSessions->at( gameIndex );
+#ifdef _WINDOWS64
+ {
+
+ int serverDbCount = 0;
+ FILE* dbFile = fopen("servers.db", "rb");
+ if (dbFile)
+ {
+ char magic[4] = {};
+ if (fread(magic, 1, 4, dbFile) == 4 && memcmp(magic, "MCSV", 4) == 0)
+ {
+ uint32_t version = 0, count = 0;
+ fread(&version, sizeof(uint32_t), 1, dbFile);
+ fread(&count, sizeof(uint32_t), 1, dbFile);
+ if (version == 1)
+ serverDbCount = static_cast<int>(count);
+ }
+ fclose(dbFile);
+ }
+ int lanCount = static_cast<int>(m_currentSessions->size()) - serverDbCount;
+ if (gameIndex >= lanCount && lanCount >= 0)
+ m_initData->serverIndex = gameIndex - lanCount;
+ else
+ m_initData->serverIndex = -1;
+ }
+#endif
- // check that we have the texture pack available
- // If it's not the default texture pack
if(m_initData->selectedSession->data.texturePackParentId!=0)
{
int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount();
@@ -1729,8 +1812,7 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
if(bHasTexturePackInstalled==false)
{
- // upsell the texture pack
- // tell sentient about the upsell of the full version of the skin pack
+
#ifdef _XBOX
ULONGLONG ullOfferID_Full;
app.GetDLCFullOfferIDForPackID(m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full);
@@ -1743,8 +1825,6 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
//uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION;
uiIDA[1]=IDS_CONFIRM_CANCEL;
-
- // Give the player a warning about the texture pack missing
ui.RequestAlertMessage(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, m_iPad,&UIScene_LoadOrJoinMenu::TexturePackDialogReturned,this);
return;
@@ -1762,7 +1842,6 @@ void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
m_controlJoinTimer.setVisible( false );
#ifdef _XBOX
- // Reset the background downloading, in case we changed it by attempting to download a texture pack
XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO);
#endif
@@ -1799,7 +1878,7 @@ void UIScene_LoadOrJoinMenu::LoadLevelGen(LevelGenerationOptions *levelGen)
NetworkGameInitData *param = new NetworkGameInitData();
param->seed = 0;
- param->saveData = NULL;
+ param->saveData = nullptr;
param->settings = app.GetGameHostOption( eGameHostOption_Tutorial );
param->levelGen = levelGen;
@@ -1818,7 +1897,7 @@ void UIScene_LoadOrJoinMenu::LoadLevelGen(LevelGenerationOptions *levelGen)
LoadingInputParams *loadingParams = new LoadingInputParams();
loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc;
- loadingParams->lpParam = (LPVOID)param;
+ loadingParams->lpParam = static_cast<LPVOID>(param);
UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData();
completionData->bShowBackground=TRUE;
@@ -1832,9 +1911,9 @@ void UIScene_LoadOrJoinMenu::LoadLevelGen(LevelGenerationOptions *levelGen)
void UIScene_LoadOrJoinMenu::UpdateGamesListCallback(LPVOID pParam)
{
- if(pParam != NULL)
+ if(pParam != nullptr)
{
- UIScene_LoadOrJoinMenu *pScene = (UIScene_LoadOrJoinMenu *)pParam;
+ UIScene_LoadOrJoinMenu *pScene = static_cast<UIScene_LoadOrJoinMenu *>(pParam);
pScene->UpdateGamesList();
}
}
@@ -1854,17 +1933,23 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
}
- FriendSessionInfo *pSelectedSession = NULL;
+ FriendSessionInfo *pSelectedSession = nullptr;
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
{
unsigned int nIndex = m_buttonListGames.getCurrentSelection();
+#ifdef _WINDOWS64
+ // Offset past the "Add Server" button
+ if (nIndex > 0)
+ pSelectedSession = m_currentSessions->at( nIndex - 1 );
+#else
pSelectedSession = m_currentSessions->at( nIndex );
+#endif
}
SessionID selectedSessionId;
ZeroMemory(&selectedSessionId,sizeof(SessionID));
- if( pSelectedSession != NULL )selectedSessionId = pSelectedSession->sessionId;
- pSelectedSession = NULL;
+ if( pSelectedSession != nullptr )selectedSessionId = pSelectedSession->sessionId;
+ pSelectedSession = nullptr;
m_controlJoinTimer.setVisible( false );
@@ -1874,12 +1959,41 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
int iY = -1;
int iX=-1;
- delete m_currentSessions;
- m_currentSessions = g_NetworkManager.GetSessionList( m_iPad, 1, m_bShowingPartyGamesOnly );
+ vector<FriendSessionInfo*>* newSessions = g_NetworkManager.GetSessionList( m_iPad, 1, m_bShowingPartyGamesOnly );
+
+ if (m_currentSessions != NULL && m_currentSessions->size() == newSessions->size())
+ {
+ bool same = true;
+ for (size_t i = 0; i < newSessions->size(); i++)
+ {
+ if (memcmp(&(*m_currentSessions)[i]->sessionId, &(*newSessions)[i]->sessionId, sizeof(SessionID)) != 0 ||
+ wcscmp((*m_currentSessions)[i]->displayLabel ? (*m_currentSessions)[i]->displayLabel : L"",
+ (*newSessions)[i]->displayLabel ? (*newSessions)[i]->displayLabel : L"") != 0)
+ {
+ same = false;
+ break;
+ }
+ }
+ if (same)
+ {
+ for (auto& it : *newSessions)
+ delete it;
+ delete newSessions;
+ return;
+ }
+ }
+
+ if (m_currentSessions)
+ {
+ for (auto& it : *m_currentSessions)
+ delete it;
+ delete m_currentSessions;
+ }
+ m_currentSessions = newSessions;
// Update the xui list displayed
unsigned int xuiListSize = m_buttonListGames.getItemCount();
- unsigned int filteredListSize = (unsigned int)m_currentSessions->size();
+ unsigned int filteredListSize = static_cast<unsigned int>(m_currentSessions->size());
BOOL gamesListHasFocus = DoesGamesListHaveFocus();
@@ -1911,6 +2025,11 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
// clear out the games list and re-fill
m_buttonListGames.clearList();
+#ifdef _WINDOWS64
+ // Always add the "Add Server" button as the first entry in the games list
+ m_buttonListGames.addItem(wstring(L"Add Server"));
+#endif
+
if( filteredListSize > 0 )
{
// Reset the focus to the selected session if it still exists
@@ -1930,12 +2049,12 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
HRESULT hr;
DWORD dwImageBytes=0;
- PBYTE pbImageData=NULL;
+ PBYTE pbImageData=nullptr;
- if(tp==NULL)
+ if(tp==nullptr)
{
DWORD dwBytes=0;
- PBYTE pbData=NULL;
+ PBYTE pbData=nullptr;
app.GetTPD(sessionInfo->data.texturePackParentId,&pbData,&dwBytes);
// is it in the tpd data ?
@@ -1976,7 +2095,12 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0)
{
+#ifdef _WINDOWS64
+ // Offset past the "Add Server" button
+ m_buttonListGames.setCurrentSelection(sessionIndex + 1);
+#else
m_buttonListGames.setCurrentSelection(sessionIndex);
+#endif
break;
}
++sessionIndex;
@@ -2134,9 +2258,9 @@ void UIScene_LoadOrJoinMenu::LoadSaveFromDisk(File *saveFile, ESavePlatform save
// Make our next save default to the name of the level
StorageManager.SetSaveTitle(saveFile->getName().c_str());
- __int64 fileSize = saveFile->length();
+ int64_t fileSize = saveFile->length();
FileInputStream fis(*saveFile);
- byteArray ba(fileSize);
+ byteArray ba(static_cast<unsigned int>(fileSize));
fis.read(ba);
fis.close();
@@ -2170,7 +2294,7 @@ void UIScene_LoadOrJoinMenu::LoadSaveFromDisk(File *saveFile, ESavePlatform save
LoadingInputParams *loadingParams = new LoadingInputParams();
loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc;
- loadingParams->lpParam = (LPVOID)param;
+ loadingParams->lpParam = static_cast<LPVOID>(param);
UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData();
completionData->bShowBackground=TRUE;
@@ -2198,7 +2322,7 @@ void UIScene_LoadOrJoinMenu::LoadSaveFromCloud()
mbstowcs(wSaveName, app.getRemoteStorage()->getSaveNameUTF8(), strlen(app.getRemoteStorage()->getSaveNameUTF8())+1); // plus null
StorageManager.SetSaveTitle(wSaveName);
- __int64 fileSize = cloudFile.length();
+ int64_t fileSize = cloudFile.length();
FileInputStream fis(cloudFile);
byteArray ba(fileSize);
fis.read(ba);
@@ -2276,7 +2400,7 @@ static bool Win64_DeleteSaveDirectory(const wchar_t* wPath)
int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
- UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)pParam;
+ UIScene_LoadOrJoinMenu* pClass = static_cast<UIScene_LoadOrJoinMenu *>(pParam);
// results switched for this dialog
// Check that we have a valid save selected (can get a bad index if the save list has been refreshed)
@@ -2298,7 +2422,7 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JSt
if (pClass->m_saveDetails && displayIdx >= 0 && pClass->m_saveDetails[displayIdx].UTF8SaveFilename[0])
{
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH] = {};
- mbstowcs_s(NULL, wFilename, MAX_SAVEFILENAME_LENGTH, pClass->m_saveDetails[displayIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
+ mbstowcs_s(nullptr, wFilename, MAX_SAVEFILENAME_LENGTH, pClass->m_saveDetails[displayIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
wchar_t wFolderPath[MAX_PATH] = {};
swprintf_s(wFolderPath, MAX_PATH, L"Windows64\\GameHDD\\%s", wFilename);
bSuccess = Win64_DeleteSaveDirectory(wFolderPath);
@@ -2322,7 +2446,7 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JSt
int UIScene_LoadOrJoinMenu::DeleteSaveDataReturned(LPVOID lpParam,bool bRes)
{
ui.EnterCallbackIdCriticalSection();
- UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)ui.GetSceneFromCallbackId((size_t)lpParam);
+ UIScene_LoadOrJoinMenu* pClass = static_cast<UIScene_LoadOrJoinMenu *>(ui.GetSceneFromCallbackId((size_t)lpParam));
if(pClass)
{
@@ -2342,7 +2466,7 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDataReturned(LPVOID lpParam,bool bRes)
int UIScene_LoadOrJoinMenu::RenameSaveDataReturned(LPVOID lpParam,bool bRes)
{
- UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)lpParam;
+ UIScene_LoadOrJoinMenu* pClass = static_cast<UIScene_LoadOrJoinMenu *>(lpParam);
if(bRes)
{
@@ -2374,7 +2498,7 @@ void UIScene_LoadOrJoinMenu::LoadRemoteFileFromDisk(char* remoteFilename)
int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
- UIScene_LoadOrJoinMenu* pClass = (UIScene_LoadOrJoinMenu*)pParam;
+ UIScene_LoadOrJoinMenu* pClass = static_cast<UIScene_LoadOrJoinMenu *>(pParam);
// results switched for this dialog
// EMessage_ResultAccept means cancel
@@ -2387,14 +2511,14 @@ int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JS
{
wchar_t wSaveName[128];
ZeroMemory(wSaveName, 128 * sizeof(wchar_t));
- mbstowcs_s(NULL, wSaveName, 128, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, _TRUNCATE);
+ mbstowcs_s(nullptr, wSaveName, 128, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, _TRUNCATE);
UIKeyboardInitData kbData;
kbData.title = app.GetString(IDS_RENAME_WORLD_TITLE);
kbData.defaultText = wSaveName;
kbData.maxChars = 25;
kbData.callback = &UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback;
kbData.lpParam = pClass;
- kbData.pcMode = !Win64_IsControllerConnected();
+ kbData.pcMode = g_KBMInput.IsKBMActive();
ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
}
#elif defined _DURANGO
@@ -2504,7 +2628,7 @@ int UIScene_LoadOrJoinMenu::MustSignInReturnedTexturePack(void *pParam,bool bCon
if(bContinue==true)
{
SONYDLC *pSONYDLCInfo=app.GetSONYDLCInfo(pClass->m_initData->selectedSession->data.texturePackParentId);
- if(pSONYDLCInfo!=NULL)
+ if(pSONYDLCInfo!=nullptr)
{
char chName[42];
char chKeyName[20];
@@ -2513,7 +2637,7 @@ int UIScene_LoadOrJoinMenu::MustSignInReturnedTexturePack(void *pParam,bool bCon
memset(chSkuID,0,SCE_NP_COMMERCE2_SKU_ID_LEN);
// we have to retrieve the skuid from the store info, it can't be hardcoded since Sony may change it.
// So we assume the first sku for the product is the one we want
- // MGH - keyname in the DLC file is 16 chars long, but there's no space for a NULL terminating char
+ // MGH - keyname in the DLC file is 16 chars long, but there's no space for a nullptr terminating char
memset(chKeyName, 0, sizeof(chKeyName));
strncpy(chKeyName, pSONYDLCInfo->chDLCKeyname, 16);
@@ -2545,7 +2669,7 @@ int UIScene_LoadOrJoinMenu::MustSignInReturnedTexturePack(void *pParam,bool bCon
int UIScene_LoadOrJoinMenu::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
- UIScene_LoadOrJoinMenu *pClass = (UIScene_LoadOrJoinMenu *)pParam;
+ UIScene_LoadOrJoinMenu *pClass = static_cast<UIScene_LoadOrJoinMenu *>(pParam);
// Exit with or without saving
if(result==C4JStorage::EMessage_ResultAccept)
@@ -2567,7 +2691,7 @@ int UIScene_LoadOrJoinMenu::TexturePackDialogReturned(void *pParam,int iPad,C4JS
#endif
SONYDLC *pSONYDLCInfo=app.GetSONYDLCInfo(pClass->m_initData->selectedSession->data.texturePackParentId);
- if(pSONYDLCInfo!=NULL)
+ if(pSONYDLCInfo!=nullptr)
{
char chName[42];
char chKeyName[20];
@@ -2576,7 +2700,7 @@ int UIScene_LoadOrJoinMenu::TexturePackDialogReturned(void *pParam,int iPad,C4JS
memset(chSkuID,0,SCE_NP_COMMERCE2_SKU_ID_LEN);
// we have to retrieve the skuid from the store info, it can't be hardcoded since Sony may change it.
// So we assume the first sku for the product is the one we want
- // MGH - keyname in the DLC file is 16 chars long, but there's no space for a NULL terminating char
+ // MGH - keyname in the DLC file is 16 chars long, but there's no space for a nullptr terminating char
memset(chKeyName, 0, sizeof(chKeyName));
strncpy(chKeyName, pSONYDLCInfo->chDLCKeyname, 16);
@@ -2610,7 +2734,7 @@ int UIScene_LoadOrJoinMenu::TexturePackDialogReturned(void *pParam,int iPad,C4JS
wstring ProductId;
app.GetDLCFullOfferIDForPackID(pClass->m_initData->selectedSession->data.texturePackParentId,ProductId);
- StorageManager.InstallOffer(1,(WCHAR *)ProductId.c_str(),NULL,NULL);
+ StorageManager.InstallOffer(1,(WCHAR *)ProductId.c_str(),nullptr,nullptr);
}
else
{
@@ -2802,7 +2926,7 @@ int UIScene_LoadOrJoinMenu::DownloadSonyCrossSaveThreadProc( LPVOID lpParameter
pMinecraft->progressRenderer->progressStart(IDS_TOOLTIPS_SAVETRANSFER_DOWNLOAD);
pMinecraft->progressRenderer->progressStage( IDS_TOOLTIPS_SAVETRANSFER_DOWNLOAD );
- ConsoleSaveFile* pSave = NULL;
+ ConsoleSaveFile* pSave = nullptr;
pClass->m_eSaveTransferState = eSaveTransfer_GetRemoteSaveInfo;
@@ -2857,10 +2981,10 @@ int UIScene_LoadOrJoinMenu::DownloadSonyCrossSaveThreadProc( LPVOID lpParameter
const char* pNameUTF8 = app.getRemoteStorage()->getSaveNameUTF8();
mbstowcs(wSaveName, pNameUTF8, strlen(pNameUTF8)+1); // plus null
StorageManager.SetSaveTitle(wSaveName);
- PBYTE pbThumbnailData=NULL;
+ PBYTE pbThumbnailData=nullptr;
DWORD dwThumbnailDataSize=0;
- PBYTE pbDataSaveImage=NULL;
+ PBYTE pbDataSaveImage=nullptr;
DWORD dwDataSizeSaveImage=0;
StorageManager.GetDefaultSaveImage(&pbDataSaveImage, &dwDataSizeSaveImage); // Get the default save thumbnail (as set by SetDefaultImages) for use on saving games t
@@ -3021,10 +3145,10 @@ int UIScene_LoadOrJoinMenu::DownloadSonyCrossSaveThreadProc( LPVOID lpParameter
StorageManager.ResetSaveData();
{
- PBYTE pbThumbnailData=NULL;
+ PBYTE pbThumbnailData=nullptr;
DWORD dwThumbnailDataSize=0;
- PBYTE pbDataSaveImage=NULL;
+ PBYTE pbDataSaveImage=nullptr;
DWORD dwDataSizeSaveImage=0;
StorageManager.GetDefaultSaveImage(&pbDataSaveImage, &dwDataSizeSaveImage); // Get the default save thumbnail (as set by SetDefaultImages) for use on saving games t
@@ -3232,7 +3356,7 @@ void UIScene_LoadOrJoinMenu::SaveTransferReturned(LPVOID lpParam, SonyRemoteStor
}
ConsoleSaveFile* UIScene_LoadOrJoinMenu::SonyCrossSaveConvert()
{
- return NULL;
+ return nullptr;
}
void UIScene_LoadOrJoinMenu::CancelSaveTransferCallback(LPVOID lpParam)
@@ -3455,7 +3579,7 @@ int UIScene_LoadOrJoinMenu::DownloadXbox360SaveThreadProc( LPVOID lpParameter )
SaveTransferStateContainer *pStateContainer = (SaveTransferStateContainer *) lpParameter;
Minecraft *pMinecraft=Minecraft::GetInstance();
- ConsoleSaveFile* pSave = NULL;
+ ConsoleSaveFile* pSave = nullptr;
while(StorageManager.SaveTransferClearState()!=C4JStorage::eSaveTransfer_Idle)
{
@@ -3542,7 +3666,7 @@ int UIScene_LoadOrJoinMenu::DownloadXbox360SaveThreadProc( LPVOID lpParameter )
bool bHostOptionsRead = false;
unsigned int uiHostOptions = 0;
DWORD dwTexturePack;
- __int64 seedVal;
+ int64_t seedVal;
char szSeed[50];
ZeroMemory(szSeed,50);
@@ -3557,7 +3681,7 @@ int UIScene_LoadOrJoinMenu::DownloadXbox360SaveThreadProc( LPVOID lpParameter )
int iTextMetadataBytes = app.CreateImageTextData(bTextMetadata, seedVal, true, uiHostOptions, dwTexturePack);
// set the icon and save image
- StorageManager.SetSaveImages(ba.data, ba.length, NULL, 0, bTextMetadata, iTextMetadataBytes);
+ StorageManager.SetSaveImages(ba.data, ba.length, nullptr, 0, bTextMetadata, iTextMetadataBytes);
delete ba.data;
}
@@ -3720,12 +3844,12 @@ void UIScene_LoadOrJoinMenu::RequestFileData( SaveTransferStateContainer *pClass
File targetFile( wstring(L"FakeTMSPP\\").append(filename) );
if(targetFile.exists())
{
- HANDLE hSaveFile = CreateFile( targetFile.getPath().c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+ HANDLE hSaveFile = CreateFile( targetFile.getPath().c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
m_debugTransferDetails.pbData = new BYTE[m_debugTransferDetails.ulFileLen];
DWORD numberOfBytesRead = 0;
- ReadFile( hSaveFile,m_debugTransferDetails.pbData,m_debugTransferDetails.ulFileLen,&numberOfBytesRead,NULL);
+ ReadFile( hSaveFile,m_debugTransferDetails.pbData,m_debugTransferDetails.ulFileLen,&numberOfBytesRead,nullptr);
assert(numberOfBytesRead == m_debugTransferDetails.ulFileLen);
CloseHandle(hSaveFile);
@@ -3753,7 +3877,7 @@ int UIScene_LoadOrJoinMenu::SaveTransferReturned(LPVOID lpParam,C4JStorage::SAVE
app.DebugPrintf("Save Transfer - size is %d\n",pSaveTransferDetails->ulFileLen);
// if the file data is null, then assume this is the file size retrieval
- if(pSaveTransferDetails->pbData==NULL)
+ if(pSaveTransferDetails->pbData==nullptr)
{
pClass->m_eSaveTransferState=C4JStorage::eSaveTransfer_FileSizeRetrieved;
UIScene_LoadOrJoinMenu::s_ulFileSize=pSaveTransferDetails->ulFileLen;
@@ -4013,3 +4137,168 @@ int UIScene_LoadOrJoinMenu::CopySaveErrorDialogFinishedCallback(void *pParam,int
}
#endif // _XBOX_ONE
+#ifdef _WINDOWS64
+// adding servers bellow
+
+void UIScene_LoadOrJoinMenu::BeginAddServer()
+{
+ m_addServerPhase = eAddServer_IP;
+ m_addServerIP.clear();
+ m_addServerPort.clear();
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Address";
+ kbData.defaultText = L"";
+ kbData.maxChars = 128;
+ kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
+ kbData.lpParam = this;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(m_iPad, eUIScene_Keyboard, &kbData);
+}
+
+int UIScene_LoadOrJoinMenu::AddServerKeyboardCallback(LPVOID lpParam, bool bRes)
+{
+ UIScene_LoadOrJoinMenu *pClass = static_cast<UIScene_LoadOrJoinMenu*>(lpParam);
+
+ if (!bRes)
+ {
+ pClass->m_addServerPhase = eAddServer_Idle;
+ pClass->m_bIgnoreInput = false;
+ return 0;
+ }
+
+ uint16_t ui16Text[256];
+ ZeroMemory(ui16Text, sizeof(ui16Text));
+ Win64_GetKeyboardText(ui16Text, 256);
+
+ wchar_t wBuf[256] = {};
+ for (int k = 0; k < 255 && ui16Text[k]; k++)
+ wBuf[k] = static_cast<wchar_t>(ui16Text[k]);
+
+ if (wBuf[0] == 0)
+ {
+ pClass->m_addServerPhase = eAddServer_Idle;
+ pClass->m_bIgnoreInput = false;
+ return 0;
+ }
+
+ switch (pClass->m_addServerPhase)
+ {
+ case eAddServer_IP:
+ {
+ pClass->m_addServerIP = wBuf;
+ pClass->m_addServerPhase = eAddServer_Port;
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Port";
+ kbData.defaultText = L"25565";
+ kbData.maxChars = 6;
+ kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
+ kbData.lpParam = pClass;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
+ break;
+ }
+ case eAddServer_Port:
+ {
+ pClass->m_addServerPort = wBuf;
+ pClass->m_addServerPhase = eAddServer_Name;
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Name";
+ kbData.defaultText = L"Minecraft Server";
+ kbData.maxChars = 64;
+ kbData.callback = &UIScene_LoadOrJoinMenu::AddServerKeyboardCallback;
+ kbData.lpParam = pClass;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
+ break;
+ }
+ case eAddServer_Name:
+ {
+ wstring name = wBuf;
+ pClass->AppendServerToFile(pClass->m_addServerIP, pClass->m_addServerPort, name);
+ pClass->m_addServerPhase = eAddServer_Idle;
+ pClass->m_bIgnoreInput = false;
+
+ g_NetworkManager.ForceFriendsSessionRefresh();
+ break;
+ }
+ default:
+ pClass->m_addServerPhase = eAddServer_Idle;
+ pClass->m_bIgnoreInput = false;
+ break;
+ }
+
+ return 0;
+}
+
+void UIScene_LoadOrJoinMenu::AppendServerToFile(const wstring& ip, const wstring& port, const wstring& name)
+{
+ char narrowIP[256] = {};
+ char narrowPort[16] = {};
+ char narrowName[256] = {};
+ wcstombs(narrowIP, ip.c_str(), sizeof(narrowIP) - 1);
+ wcstombs(narrowPort, port.c_str(), sizeof(narrowPort) - 1);
+ wcstombs(narrowName, name.c_str(), sizeof(narrowName) - 1);
+
+ uint16_t portNum = static_cast<uint16_t>(atoi(narrowPort));
+
+ struct ServerEntry { std::string ip; uint16_t port; std::string name; };
+ std::vector<ServerEntry> entries;
+
+ FILE* file = fopen("servers.db", "rb");
+ if (file)
+ {
+ char magic[4] = {};
+ if (fread(magic, 1, 4, file) == 4 && memcmp(magic, "MCSV", 4) == 0)
+ {
+ uint32_t version = 0, count = 0;
+ fread(&version, sizeof(uint32_t), 1, file);
+ fread(&count, sizeof(uint32_t), 1, file);
+ if (version == 1)
+ {
+ for (uint32_t s = 0; s < count; s++)
+ {
+ uint16_t ipLen = 0, p = 0, nameLen = 0;
+ if (fread(&ipLen, sizeof(uint16_t), 1, file) != 1) break;
+ if (ipLen == 0 || ipLen > 256) break;
+ char ipBuf[257] = {};
+ if (fread(ipBuf, 1, ipLen, file) != ipLen) break;
+ if (fread(&p, sizeof(uint16_t), 1, file) != 1) break;
+ if (fread(&nameLen, sizeof(uint16_t), 1, file) != 1) break;
+ if (nameLen > 256) break;
+ char nameBuf[257] = {};
+ if (nameLen > 0 && fread(nameBuf, 1, nameLen, file) != nameLen) break;
+ entries.push_back({std::string(ipBuf), p, std::string(nameBuf)});
+ }
+ }
+ }
+ fclose(file);
+ }
+
+ entries.push_back({std::string(narrowIP), portNum, std::string(narrowName)});
+
+ file = fopen("servers.db", "wb");
+ if (file)
+ {
+ fwrite("MCSV", 1, 4, file);
+ uint32_t version = 1;
+ uint32_t count = static_cast<uint32_t>(entries.size());
+ fwrite(&version, sizeof(uint32_t), 1, file);
+ fwrite(&count, sizeof(uint32_t), 1, file);
+
+ for (size_t i = 0; i < entries.size(); i++)
+ {
+ uint16_t ipLen = static_cast<uint16_t>(entries[i].ip.length());
+ fwrite(&ipLen, sizeof(uint16_t), 1, file);
+ fwrite(entries[i].ip.c_str(), 1, ipLen, file);
+ fwrite(&entries[i].port, sizeof(uint16_t), 1, file);
+ uint16_t nameLen = static_cast<uint16_t>(entries[i].name.length());
+ fwrite(&nameLen, sizeof(uint16_t), 1, file);
+ fwrite(entries[i].name.c_str(), 1, nameLen, file);
+ }
+ fclose(file);
+ }
+}
+#endif // _WINDOWS64 \ No newline at end of file