aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common/UI
diff options
context:
space:
mode:
authorMatthew Toro <48634881+mattsumi@users.noreply.github.com>2026-03-08 04:10:15 -0400
committerGitHub <noreply@github.com>2026-03-08 03:10:15 -0500
commit3a5f1b617931d00145504d97ef4fbef4f3138b5b (patch)
tree925a71e25f2b9256f85c50833585a791e44771de /Minecraft.Client/Common/UI
parentd461012efb3855d1fbfe9dc3696562223f21334a (diff)
Add "Add Server" functionally to "Join Game" Menu + relocate servers.txt to servers.db. (#911)
* Add "Add Server" functionally to "Join Game" Menu + relocate servers.txt to servers.db * enchancement: add edit and delete server functionality, solves FriendSessionInfo corruption issues
Diffstat (limited to 'Minecraft.Client/Common/UI')
-rw-r--r--Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp340
-rw-r--r--Minecraft.Client/Common/UI/UIScene_JoinMenu.h19
-rw-r--r--Minecraft.Client/Common/UI/UIScene_Keyboard.cpp45
-rw-r--r--Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp279
-rw-r--r--Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h12
-rw-r--r--Minecraft.Client/Common/UI/UIStructs.h3
6 files changed, 666 insertions, 32 deletions
diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp
index 6e354922..ccb572b8 100644
--- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp
@@ -21,12 +21,19 @@ UIScene_JoinMenu::UIScene_JoinMenu(int iPad, void *_initData, UILayer *parentLay
m_friendInfoUpdatedOK = false;
m_friendInfoUpdatedERROR = false;
m_friendInfoRequestIssued = false;
+#ifdef _WINDOWS64
+ m_serverIndex = initData->serverIndex;
+ m_editServerPhase = eEditServer_Idle;
+ m_editServerButtonIndex = -1;
+ m_deleteServerButtonIndex = -1;
+#endif
}
void UIScene_JoinMenu::updateTooltips()
{
int iA = -1;
int iY = -1;
+ int iX = -1;
if (getControlFocus() == eControl_GamePlayers)
{
#ifdef _DURANGO
@@ -38,7 +45,15 @@ void UIScene_JoinMenu::updateTooltips()
iA = IDS_TOOLTIPS_SELECT;
}
- ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA, IDS_TOOLTIPS_BACK, -1, iY );
+#ifdef _WINDOWS64
+ if (m_serverIndex >= 0)
+ {
+ iX = IDS_TOOLTIPS_DELETE;
+ iY = IDS_TITLE_RENAME;
+ }
+#endif
+
+ ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA, IDS_TOOLTIPS_BACK, iX, iY );
}
@@ -107,6 +122,16 @@ void UIScene_JoinMenu::tick()
}
#endif
+#ifdef _WINDOWS64
+ if (m_serverIndex >= 0)
+ {
+ m_editServerButtonIndex = m_buttonListPlayers.getItemCount();
+ m_buttonListPlayers.addItem(L"Edit Server");
+ m_deleteServerButtonIndex = m_buttonListPlayers.getItemCount();
+ m_buttonListPlayers.addItem(L"Delete Server");
+ }
+#endif
+
m_labelLabels[eLabel_Difficulty].init(app.GetString(IDS_LABEL_DIFFICULTY));
m_labelLabels[eLabel_GameType].init(app.GetString(IDS_LABEL_GAME_TYPE));
m_labelLabels[eLabel_GamertagsOn].init(app.GetString(IDS_LABEL_GAMERTAGS));
@@ -279,11 +304,37 @@ void UIScene_JoinMenu::handleInput(int iPad, int key, bool repeat, bool pressed,
}
break;
#endif
+#ifdef _WINDOWS64
+ case ACTION_MENU_X:
+ if(pressed && m_serverIndex >= 0)
+ {
+ BeginDeleteServer();
+ handled = true;
+ }
+ break;
+ case ACTION_MENU_Y:
+ if(pressed && m_serverIndex >= 0)
+ {
+ BeginEditServer();
+ handled = true;
+ }
+ break;
+#endif
case ACTION_MENU_OK:
if (getControlFocus() != eControl_GamePlayers)
{
sendInputToMovie(key, repeat, pressed, released);
}
+#ifdef _WINDOWS64
+ else if (pressed && m_serverIndex >= 0)
+ {
+ int sel = m_buttonListPlayers.getCurrentSelection();
+ if (sel == m_editServerButtonIndex)
+ BeginEditServer();
+ else if (sel == m_deleteServerButtonIndex)
+ BeginDeleteServer();
+ }
+#endif
handled = true;
break;
#ifdef __ORBIS__
@@ -318,6 +369,16 @@ void UIScene_JoinMenu::handlePress(F64 controlId, F64 childId)
}
break;
case eControl_GamePlayers:
+#ifdef _WINDOWS64
+ if (m_serverIndex >= 0)
+ {
+ int sel = (int)childId;
+ if (sel == m_editServerButtonIndex)
+ BeginEditServer();
+ else if (sel == m_deleteServerButtonIndex)
+ BeginDeleteServer();
+ }
+#endif
break;
};
}
@@ -635,4 +696,279 @@ void UIScene_JoinMenu::handleTimerComplete(int id)
}
break;
};
-} \ No newline at end of file
+}
+
+#ifdef _WINDOWS64
+void UIScene_JoinMenu::BeginDeleteServer()
+{
+ m_bIgnoreInput = true;
+ UINT uiIDA[2];
+ uiIDA[0] = IDS_CONFIRM_CANCEL;
+ uiIDA[1] = IDS_CONFIRM_OK;
+ ui.RequestAlertMessage(IDS_TOOLTIPS_DELETE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, m_iPad, &UIScene_JoinMenu::DeleteServerDialogReturned, this);
+}
+
+int UIScene_JoinMenu::DeleteServerDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result)
+{
+ UIScene_JoinMenu* pClass = (UIScene_JoinMenu*)pParam;
+
+ if (result == C4JStorage::EMessage_ResultDecline)
+ {
+ pClass->RemoveServerFromFile();
+ g_NetworkManager.ForceFriendsSessionRefresh();
+ pClass->navigateBack();
+ }
+ else
+ {
+ pClass->m_bIgnoreInput = false;
+ }
+
+ return 0;
+}
+
+void UIScene_JoinMenu::BeginEditServer()
+{
+ m_bIgnoreInput = true;
+ m_editServerPhase = eEditServer_IP;
+ m_editServerIP.clear();
+ m_editServerPort.clear();
+
+ wchar_t wDefaultIP[64] = {};
+ mbstowcs(wDefaultIP, m_selectedSession->data.hostIP, 63);
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Address";
+ kbData.defaultText = wDefaultIP;
+ kbData.maxChars = 128;
+ kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
+ kbData.lpParam = this;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(m_iPad, eUIScene_Keyboard, &kbData);
+}
+
+int UIScene_JoinMenu::EditServerKeyboardCallback(LPVOID lpParam, bool bRes)
+{
+ UIScene_JoinMenu *pClass = (UIScene_JoinMenu *)lpParam;
+
+ if (!bRes)
+ {
+ pClass->m_editServerPhase = eEditServer_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] = (wchar_t)ui16Text[k];
+
+ if (wBuf[0] == 0)
+ {
+ pClass->m_editServerPhase = eEditServer_Idle;
+ pClass->m_bIgnoreInput = false;
+ return 0;
+ }
+
+ switch (pClass->m_editServerPhase)
+ {
+ case eEditServer_IP:
+ {
+ pClass->m_editServerIP = wBuf;
+ pClass->m_editServerPhase = eEditServer_Port;
+
+ wchar_t wDefaultPort[16] = {};
+ swprintf(wDefaultPort, 16, L"%d", pClass->m_selectedSession->data.hostPort);
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Port";
+ kbData.defaultText = wDefaultPort;
+ kbData.maxChars = 6;
+ kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
+ kbData.lpParam = pClass;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
+ break;
+ }
+ case eEditServer_Port:
+ {
+ pClass->m_editServerPort = wBuf;
+ pClass->m_editServerPhase = eEditServer_Name;
+
+ wchar_t wDefaultName[64] = {};
+ if (pClass->m_selectedSession->displayLabel)
+ wcsncpy(wDefaultName, pClass->m_selectedSession->displayLabel, 63);
+
+ UIKeyboardInitData kbData;
+ kbData.title = L"Server Name";
+ kbData.defaultText = wDefaultName;
+ kbData.maxChars = 64;
+ kbData.callback = &UIScene_JoinMenu::EditServerKeyboardCallback;
+ kbData.lpParam = pClass;
+ kbData.pcMode = g_KBMInput.IsKBMActive();
+ ui.NavigateToScene(pClass->m_iPad, eUIScene_Keyboard, &kbData);
+ break;
+ }
+ case eEditServer_Name:
+ {
+ wstring newName = wBuf;
+ pClass->UpdateServerInFile(pClass->m_editServerIP, pClass->m_editServerPort, newName);
+ pClass->m_editServerPhase = eEditServer_Idle;
+ pClass->m_bIgnoreInput = false;
+
+ g_NetworkManager.ForceFriendsSessionRefresh();
+ pClass->navigateBack();
+ break;
+ }
+ default:
+ pClass->m_editServerPhase = eEditServer_Idle;
+ pClass->m_bIgnoreInput = false;
+ break;
+ }
+
+ return 0;
+}
+
+void UIScene_JoinMenu::UpdateServerInFile(const wstring& newIP, const wstring& newPort, const wstring& newName)
+{
+ char narrowNewIP[256] = {};
+ char narrowNewPort[16] = {};
+ char narrowNewName[256] = {};
+ wcstombs(narrowNewIP, newIP.c_str(), sizeof(narrowNewIP) - 1);
+ wcstombs(narrowNewPort, newPort.c_str(), sizeof(narrowNewPort) - 1);
+ wcstombs(narrowNewName, newName.c_str(), sizeof(narrowNewName) - 1);
+
+ uint16_t newPortNum = (uint16_t)atoi(narrowNewPort);
+
+ 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);
+ }
+
+ // Find and update the matching entry by original IP and port
+ int idx = m_serverIndex;
+ if (idx >= 0 && idx < (int)entries.size())
+ {
+ entries[idx].ip = std::string(narrowNewIP);
+ entries[idx].port = newPortNum;
+ entries[idx].name = std::string(narrowNewName);
+ }
+
+ file = fopen("servers.db", "wb");
+ if (file)
+ {
+ fwrite("MCSV", 1, 4, file);
+ uint32_t version = 1;
+ uint32_t count = (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 = (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 = (uint16_t)entries[i].name.length();
+ fwrite(&nameLen, sizeof(uint16_t), 1, file);
+ fwrite(entries[i].name.c_str(), 1, nameLen, file);
+ }
+ fclose(file);
+ }
+}
+
+void UIScene_JoinMenu::RemoveServerFromFile()
+{
+ 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);
+ }
+
+ // Remove the entry at m_serverIndex
+ int idx = m_serverIndex;
+ if (idx >= 0 && idx < (int)entries.size())
+ {
+ entries.erase(entries.begin() + idx);
+ }
+
+ file = fopen("servers.db", "wb");
+ if (file)
+ {
+ fwrite("MCSV", 1, 4, file);
+ uint32_t version = 1;
+ uint32_t count = (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 = (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 = (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
diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.h b/Minecraft.Client/Common/UI/UIScene_JoinMenu.h
index 817360ef..566697cd 100644
--- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.h
+++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.h
@@ -62,6 +62,16 @@ private:
bool m_friendInfoUpdatedOK;
bool m_friendInfoUpdatedERROR;
+#ifdef _WINDOWS64
+ int m_serverIndex; // Index in servers.db, -1 if not a saved server
+ enum eEditServerPhase { eEditServer_Idle, eEditServer_IP, eEditServer_Port, eEditServer_Name };
+ eEditServerPhase m_editServerPhase;
+ wstring m_editServerIP;
+ wstring m_editServerPort;
+ int m_editServerButtonIndex;
+ int m_deleteServerButtonIndex;
+#endif
+
public:
UIScene_JoinMenu(int iPad, void *initData, UILayer *parentLayer);
void tick();
@@ -95,4 +105,13 @@ protected:
static int StartGame_SignInReturned(void *pParam, bool, int);
static void JoinGame(UIScene_JoinMenu* pClass);
+
+#ifdef _WINDOWS64
+ void BeginEditServer();
+ void BeginDeleteServer();
+ static int EditServerKeyboardCallback(LPVOID lpParam, bool bRes);
+ static int DeleteServerDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result);
+ void UpdateServerInFile(const wstring& newIP, const wstring& newPort, const wstring& newName);
+ void RemoveServerFromFile();
+#endif
};
diff --git a/Minecraft.Client/Common/UI/UIScene_Keyboard.cpp b/Minecraft.Client/Common/UI/UIScene_Keyboard.cpp
index b28564c3..0af343bb 100644
--- a/Minecraft.Client/Common/UI/UIScene_Keyboard.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_Keyboard.cpp
@@ -229,27 +229,31 @@ void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed,
handled = true;
break;
case ACTION_MENU_X: // X
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcBackspaceButtonPressed, 0 , NULL );
- handled = true;
- break;
case ACTION_MENU_PAGEUP: // LT
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSymbolButtonPressed, 0 , NULL );
- handled = true;
- break;
case ACTION_MENU_Y: // Y
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSpaceButtonPressed, 0 , NULL );
- handled = true;
- break;
case ACTION_MENU_STICK_PRESS: // LS
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCapsButtonPressed, 0 , NULL );
- handled = true;
- break;
case ACTION_MENU_LEFT_SCROLL: // LB
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorLeftButtonPressed, 0 , NULL );
- handled = true;
- break;
case ACTION_MENU_RIGHT_SCROLL: // RB
- out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorRightButtonPressed, 0 , NULL );
+#ifdef _WINDOWS64
+
+ if (m_bPCMode)
+ {
+ handled = true;
+ break;
+ }
+#endif
+ if (key == ACTION_MENU_X)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcBackspaceButtonPressed, 0 , NULL );
+ else if (key == ACTION_MENU_PAGEUP)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSymbolButtonPressed, 0 , NULL );
+ else if (key == ACTION_MENU_Y)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSpaceButtonPressed, 0 , NULL );
+ else if (key == ACTION_MENU_STICK_PRESS)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCapsButtonPressed, 0 , NULL );
+ else if (key == ACTION_MENU_LEFT_SCROLL)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorLeftButtonPressed, 0 , NULL );
+ else if (key == ACTION_MENU_RIGHT_SCROLL)
+ out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcCursorRightButtonPressed, 0 , NULL );
handled = true;
break;
case ACTION_MENU_PAUSEMENU: // Start
@@ -269,6 +273,15 @@ void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed,
switch(key)
{
case ACTION_MENU_OK:
+#ifdef _WINDOWS64
+ if (m_bPCMode)
+ {
+ // pressing enter sometimes causes a "y" to be entered.
+ handled = true;
+ break;
+ }
+#endif
+ // fall through for controller mode
case ACTION_MENU_LEFT:
case ACTION_MENU_RIGHT:
case ACTION_MENU_UP:
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
index 00462a90..a0498d5f 100644
--- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
@@ -402,8 +402,13 @@ UIScene_LoadOrJoinMenu::~UIScene_LoadOrJoinMenu()
g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL );
app.SetLiveLinkRequired( false );
- delete m_currentSessions;
- m_currentSessions = NULL;
+ if (m_currentSessions)
+ {
+ for (auto& it : *m_currentSessions)
+ delete it;
+ delete m_currentSessions;
+ m_currentSessions = NULL;
+ }
#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;
@@ -1051,8 +1059,7 @@ void UIScene_LoadOrJoinMenu::GetSaveInfo()
m_pSaveDetails=StorageManager.ReturnSavesInfo();
if(m_pSaveDetails==NULL)
{
- char savename[] = "save";
- C4JStorage::ESaveGameState eSGIStatus = StorageManager.GetSavesInfo(m_iPad, NULL, this, savename);
+ C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad,NULL,this,"save");
}
#if TO_BE_IMPLEMENTED
@@ -1471,6 +1478,10 @@ void UIScene_LoadOrJoinMenu::handleFocusChange(F64 controlId, F64 childId)
{
case eControl_GamesList:
m_iGameListIndex = childId;
+#ifdef _WINDOWS64
+ // Offset past the "Add Server" button so m_iGameListIndex is a session index
+ m_iGameListIndex -= 1;
+#endif
m_buttonListGames.updateChildFocus( (int) childId );
break;
case eControl_SavesList:
@@ -1598,6 +1609,14 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
break;
case eControl_GamesList:
{
+#ifdef _WINDOWS64
+ if ((int)childId == ADD_SERVER_BUTTON_INDEX)
+ {
+ ui.PlayUISFX(eSFX_Press);
+ BeginAddServer();
+ break;
+ }
+#endif
m_bIgnoreInput=true;
m_eAction = eAction_JoinGame;
@@ -1607,6 +1626,10 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
{
int nIndex = (int)childId;
+#ifdef _WINDOWS64
+ // Offset by 1 because the "Add Server" button is at index 0
+ nIndex -= 1;
+#endif
m_iGameListIndex = nIndex;
CheckAndJoinGame(nIndex);
}
@@ -1744,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 = (int)count;
+ }
+ fclose(dbFile);
+ }
+ int lanCount = (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();
@@ -1767,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);
@@ -1781,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;
@@ -1800,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
@@ -1896,7 +1937,13 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
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;
@@ -1912,8 +1959,37 @@ 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();
@@ -1949,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
@@ -2014,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;
@@ -4051,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 = (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] = (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 = (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 = (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 = (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 = (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
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h
index 3599aa37..9f5fe17f 100644
--- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h
+++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h
@@ -175,6 +175,18 @@ public:
private:
void CheckAndJoinGame(int gameIndex);
+
+#ifdef _WINDOWS64
+ static const int ADD_SERVER_BUTTON_INDEX = 0;
+ enum eAddServerPhase { eAddServer_Idle, eAddServer_IP, eAddServer_Port, eAddServer_Name };
+ eAddServerPhase m_addServerPhase;
+ wstring m_addServerIP;
+ wstring m_addServerPort;
+ void BeginAddServer();
+ void AppendServerToFile(const wstring& ip, const wstring& port, const wstring& name);
+ static int AddServerKeyboardCallback(LPVOID lpParam, bool bRes);
+#endif
+
#if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__)
static int MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result);
static int PSN_SignInReturned(void *pParam,bool bContinue, int iPad);
diff --git a/Minecraft.Client/Common/UI/UIStructs.h b/Minecraft.Client/Common/UI/UIStructs.h
index ac83458f..b3422832 100644
--- a/Minecraft.Client/Common/UI/UIStructs.h
+++ b/Minecraft.Client/Common/UI/UIStructs.h
@@ -280,6 +280,9 @@ typedef struct _JoinMenuInitData
{
FriendSessionInfo *selectedSession;
int iPad;
+#ifdef _WINDOWS64
+ int serverIndex; // Index of the server in servers.db, -1 if not a saved server
+#endif
} JoinMenuInitData;
// Native keyboard (Windows64 replacement for InputManager.RequestKeyboard WinAPI dialog)